2007/03/14

AJAX 上一頁問題 Part.2

沒想到才貼出幾小時就有迴響,感覺還不錯。昨日研究了一些函式庫後,發現其實要修補這個上一頁問題也十分容易。但坊間很多函式庫都是跟什麼大函式庫綁在一起,有殺雞用牛刀的感覺。或有的雖然不是綁在函式庫上,但是本體又大又難懂。直到真正懂了原理後,自己能作出剛好夠用的函式,處理範圍就只有歷史物件,其他的交給你自己吧!

再更詳細的談一下處理 AJAX Backward / Forward 上(下)一頁問題的關鍵:

1. 因為使用 AJAX 會造成實質上網頁沒有改位置 (location.href),因此傳統的瀏覽器歷史並無法作用。但是這時候如果改變錨點 (location.hash),卻能使 Firefox / Opera 瀏覽器的瀏覽器歷史產生改變,IE 比較奇怪,單純改變錨點是不會改動到瀏覽器歷史,不過如果有 iframe 內嵌頁框輔助,以它的頁面改變來使瀏覽器的歷史物件改變,卻能成功。因此我們可以知道以錨點或 iframe 來模擬傳統改變頁面位置的做法,進而使瀏覽器歷史又活了起來。

2. 活了之後還是沒有用。你發現雖然上一頁可以按了,但按了卻也沒效果。因為以 DOM 改變頁面元素的做法,瀏覽器歷史不會幫你還原,而傳統的頁面更換,瀏覽器卻能幫你更改頁面位置。也就是說我們只成功了一半。成功哪邊呢?瀏覽器歷史的再啟用 (Reactivate)。仔細看可以發現,按了上一頁按鈕後,頁面位置 / iframe 頁面的錨點是有改變的,假如說有個 onhashchange 事件,我們就能捕捉當 index.htm#play -> index.htm#stop 的改變時,能夠做點動作。方法是 setInterval ,以某個檢查器每隔一段時間偵測錨點改變沒,當一改變即觸動我們所謂的 onhashchange 事件。

3. 有了我們需要的 onhashchange 這種事件後,只需要在這時用一個控制函式判斷目前錨點是什麼,就可以進行對應內容。例如 #play 可能是開啟什麼資源印出來, #stop 就是把印出來的東西清掉。所有的動作全利用這個控制函式即可。連結只需要作改變錨點 / iframe頁面錨點的動作就可以很輕鬆了。

4. 來談談讓 IE 怎麼以 iframe 模擬吧。以前的做法是讓 iframe 的 src 改變,例如說 blank.htm?play -> blank.htm?stop,最近的好方法改成使用 IE 的密技,也就是打開 iframe 文件物件再關閉,這樣可以產生一個虛頁面 (頁面位置根本不存在,純為臨時創立),再改變這個頁面的 Hash 值當作記錄就可以了。當要再改變時,再開一次文件物件、關閉、設定錨點,IE 會以為頁面位置改變了,於是瀏覽器記錄就加了一筆。而按上一頁按鈕之時,錨點就會改變,成功模擬出我們要的效果。

5. 其實用這個方法又順便解決了 AJAX 沒有永久連結的設計,因為是 DOM 改變頁面元素,所以預設不會有一個 URL 資源對應目前頁面的狀態。用了 Hash 後就能成功解決。只要在頁面一載入之時把目前頁面的 Hash 丟給 3. 提到的控制函式處理,不就得了?所以 onhashchange 執行時機有二 (1. 頁面 Hash 因瀏覽器上一頁或操作而改變時 2.一開始進入頁面網址有添附 Hash 時)
---
這裡有一個簡單的範例,大家可以試試:pHistory
原始碼應該很好懂,其中註冊歷史 (pHistory.register) 是給 IE 暗中去改變 iframe 用的。關鍵就在檢查器而已。

這個範例還不支援 Safari,因為其行為較為特殊,手上也沒樣本可以觀察。

6 則留言:

  1. pHistory在Swift 0.2(KHTML+KJS/AppleWebKit 420+) 上成功運作
    但是不知道在Konqueror和Safari中是不是也正常呢

    回覆刪除
  2. 這個 Swift 用 Google 都找到車子去了,好不容易搜到 0.2 版。
    很陽春,但潛力無限啊。
    試驗的確可行,不過我記得 Safari 的歷史物件比較奇怪,jQuery.history 還特別寫適應用程式碼。
    不過如果是 WebKit 新版直接支援那也省功啦。

    裝 Konqueror 的 VPC 2007 怪掉了開不了無法測,Safari 嘛,手上不可能找來測。

    等我有空就對這個 Blog 做做 Hash Permanent URL 修正吧。

    回覆刪除
  3. 發現 IE 在剛進入時會轉移焦點到網頁下方,不太方便,今天修正了這個錯誤。

    另外,也把其成果實裝於 Pixmicat!2 上了 (當然是開發中版本)。

    回覆刪除
  4. 修正 IE iframe 在一開始載入時捲軸仍有少數偏移的問題
    (焦點捲至最下→位於開頭稍偏移→頂端)
    應該在於 iframe 改變內容時會取得焦點,造成捲軸移動。
    現強制以 window.scroll(0, 0); 修正。

    回覆刪除
  5. 如此者解決了上一頁的問題
    但 書籤 的問題怎樣解決?
    可否分享一下相關的資料?

    我在網上也只找到RSH及以下文章
    http://www.contentwithstyle.co.uk/Articles/38/fixing-the-back-button-and-enabling-bookmarking-for-ajax-apps

    回覆刪除
  6. 第5.點就解決了你所關心的Bookmark問題。
    注意一下我的範例,那個連結可是一開始就有附加錨點的,進去之後就會觸發自訂事件。

    其原理就是利用錨點更改跟定期檢查錨點的機制去達成的。

    回覆刪除