history 物件儲存了庫互動瀏覽器的瀏覽歷史,通過 window 物件的 history 屬性可以存取該物件,實際上 history 屬性僅儲存最近存取的、有限條目的 URL 資訊。
在 HTML5 之前,為了保護用戶端瀏覽資訊的安全和隱私,history 物件禁止 JavaScript 指令碼直接操作這些存取資訊。不過 HTML5 新增了一個 History API,該 API 允許使用者通過 JavaScript 管理瀏覽器的歷史記錄,實現無重新整理更改瀏覽器位址列的地址,配合 History + Ajax 可以設計不需要重新整理頁面的跳轉。
操作歷史記錄
在歷史記錄中後退
window.history.back();1
這行程式碼等效於在瀏覽器的工具列上單擊“返回”按鈕。
在歷史記錄中前進
window.history.forward();1
這行程式碼等效於瀏覽器中單擊“前進”按鈕。
移動到指定的歷史記錄點
使用 go() 方法從當前對談的歷史記錄中載入頁面。當前頁面位置索引值為 0,上一頁就是 -1,下一頁為 1,以此類推。
window.history.go(-1); //相當於呼叫 back()
window.history.go(1); //相當於呼叫forward()
length 屬性
使用 length 屬性可以了解歷史記錄棧中一共有多少頁。
var num = window.history.length;
新增和修改歷史記錄條目
HTML5 新增 history.pushState() 和 history.replaceState() 方法,允許使用者逐條新增和修改歷史記錄條目。
使用 history.pushState() 方法可以改變 referrer 的值,而在呼叫該方法後建立的 XMLHttpRequest 物件會在 HTTP 請求頭中使用這個值。referrer 的值則是建立 XMLHttpRequest 物件時所處的視窗的 URL。
【範例】假設 http://123.com/foo.html 頁面將執行下面 JavaScript 程式碼。
var stateObj = {foo : "bar"};
history.pushState (stateObj, "page 2", "bar.html");
這時瀏覽器的位址列將顯示 http://123.com/bar.html,但不會載入 bar.html 頁面,也不會檢查 bar.html 是否存在。
如果現在導航到 http://123.com/ 頁面,然後單擊“後退”按鈕,此時位址列會顯示 http://123.com/bar.html,並且會觸發 popstate 事件,該事件中的狀態物件會包含 stateObj 的一個拷貝。
如果再次單擊“後退”按鈕,URL 將返回 http://123.com/foo.html,文件將觸發另一個 popstate 事件,這次的狀態物件為 null,回退同樣不會改變文件內容。
pushState() 方法
pushState() 方法包含 3 個引數,簡單說明如下:
-
狀態物件。狀態物件是一個 JavaScript 物件直接量,與呼叫 pushState() 方法建立的新歷史記錄條目相關聯。無論何時使用者導航到新建立的狀態,popstate 事件都會被觸發,並且事件物件的 state 屬性都包含歷史記錄條目的狀態物件的拷貝。
-
標題。可以傳入一個簡短的標題,標明將要進入的狀態。FireFox 瀏覽器目前忽略該引數,考慮到未來可能會對該方法進行修改,傳一個空字串會比較安全。
-
可選引數。新的歷史記錄條目的地址。
瀏覽器不會在呼叫 pushState() 方法後載入該地址,如果不指定則為文件當前 URL。
呼叫 pushState() 方法類似於設定 window.location='#foo',它們都會在當前文件內建立和啟用新的歷史記錄條目。但 pushState() 有自己的優勢。
-
新的 URL 可以是任意的同源 URL。相反,使用 window.location 方法時,只有僅修改 hash 才能保證停留在相同的 document 中。
-
根據個人需要決定是否修改 URL。相反,設定 window.location='#foo',只有在當前 hash 值不是 foo 時才建立一條新的歷史記錄。
-
可以在新的歷史記錄條目中新增抽象資料。如果使用基於 hash 的方法,只能把相關資料轉碼成一個很短的字串。
pushState() 方法永遠不會觸發 hashchange 事件。
replaceState() 方法
history.replaceState() 與 history.pushState() 用法相同,都包含 3 個相同的引數。不同之處是:pushState() 是在 history 棧中新增一個新的條目,replaceState() 是替換當前的記錄值。例如,history 棧中有兩個棧塊,一個標記為 1,另一個標記為 2,現在有第 3 個棧塊,標記為 3。當執行 pushState() 時,棧塊 3 將被新增棧中,棧就有 3 個棧塊了;而當執行 replaceState() 時,將使用棧塊 3 替換當前啟用的棧塊 2,history 的記錄條數不變。也就是說,pushState() 會讓 history 的數量加 1。
為了響應使用者的某些操作,需要更新當前歷史記錄條目的狀態物件或 URL 時,使用 replaceState() 方法會特別合適。
popstate 事件
每當啟用的歷史記錄發生變化時,都會觸發 popstate 事件。如果被啟用的歷史記錄條目是由 pushState() 建立,或者是被 replaceState() 方法替換的,popstate 事件的狀態屬性將包含歷史記錄的狀態物件的一個拷貝。
當瀏覽對談歷史記錄時,不管是單擊瀏覽器工具列中的“前進”或者“後退”按鈕,還是使用 JavaScript 的 history.go() 和 history.back() 方法,popstate 事件都會被觸發。
讀取歷史狀態
在頁面載入時,可能會包含一個非空的狀態物件。這種情況是會發生的,例如,如果頁面中使用 pushState() 或 replaceState() 方法設定了一個狀態物件,然後重新啟動瀏覽器。當頁面重新載入時,頁面會觸發 onload 事件,但不會觸發 popstate 事件。但是,如果讀取 history.state 屬性,會得到一個與 popstate 事件觸發時一樣的狀態物件。
可以直接讀取當前歷史記錄條目的狀態,而不需要等待 popstate 事件。
var currentState = history.state;
案例:設計無重新整理導航
本例設計一個無重新整理頁面導航,在首頁(index.html)包含一個導航列表,當使用者單擊不同的列表專案時,首頁(index.html)的內容容器(<div id="content">)會自動更新內容,正確顯示對應目標頁面的 HTML 內容,同時瀏覽器位址列正確顯示目標頁面的 URL(但是首頁並沒有被重新整理),而不是僅顯示目標頁面。顯示效果如圖所示。