History物件允許我們操作瀏覽器會話歷史,即載入當前頁面的標籤頁視窗或frame視窗的訪問歷史。之前有同學諮詢我如何實現攔截使用者跳轉頁面並強制使用者返回首頁後重新請求頁面,於是有了本篇部落格的主題,本篇深入介紹瀏覽器會話歷史的操作,在最後對比載入頁面的幾種不同方式,並提供一個例項給讀者把玩。
屬性
History.length
只讀的,其值為一個整數,標誌包括當前頁面在內的會話歷史中的記錄數量,比如我們通常開啟一個空白視窗,length為0,再訪問一個頁面,其length變為1。
History.scrollRestoration
允許web應用在會話歷史導航時顯式地設定預設滾動復原,其值為auto或manual。
History.state
只讀,返回代表會話歷史堆疊頂部記錄的任意可序列化型別資料值,我們可以以此來區別不同會話歷史紀錄。
方法
History.back()
返回會話歷史記錄中的上一個頁面,等價於window.history.go(-1)和點選瀏覽器的後退按鈕。
History.forward()
進入會話歷史記錄中的下一個頁面,等價於window.history.go(1)和點選瀏覽器的前進按鈕。
History.go()
載入會話歷史記錄中的某一個頁面,通過該頁面與當前頁面在會話歷史中的相對位置定位,如,-1代表當前頁面的上一個記錄,1代表當前頁面的下一個頁面。若不傳引數或傳入0,則會重新載入當前頁面;若引數超出當前會話歷史紀錄數,則不進行操作。
History pushState()
在會話歷史堆疊頂部插入一條記錄,引數包括,任意可序列化的object物件資料(可選),頁面標題(可選),頁面URL(非空)。
目前,Firefox忽略頁面標題引數。
History.replaceState()
更新會話歷史堆疊頂部記錄資訊,包括特定的任意可序列化的object物件資料(可選),頁面標題(可選),頁面URL。
值得注意的是,無論是replaceState()方法還是pushState()方法,其更新或新增會話歷史記錄後,改變的只是瀏覽器關於當前頁面的標題和URL的記錄情況,並不會重新整理或改變頁面展示。
window.history
window的history是隻讀屬性,該屬性返回History物件的一個引用,支援我們操作瀏覽器會話歷史記錄。
出於安全考慮,History物件不允許我們通過JavaScript程式碼訪問其他會話歷史記錄中其他頁面的URL,但是它允許我們在不同頁面間進行導航。
onpopstate事件
HTML5中,提供history.pushState()和history.replaceState()方法,支援我們新增或更新會話歷史記錄,另外還提供window.onpopstate事件支援我們對該操作進行監聽。
pushState()
pushState()方法接收三個引數,一個state物件,一個頁面標題,一個URL:
狀態物件:
- 儲存新添會話歷史記錄的狀態資訊物件,每次訪問該條會話時,都會觸發popstate事件,並且事件回撥函式會接收一個引數,值為該事件物件的複製副本;
- 狀態物件可以是任何可序列化的資料,瀏覽器將狀態物件儲存在使用者的磁碟以便使用者再次重啟瀏覽器時能恢復資料;
- 一個狀態物件序列化後的最大長度是640K,如果傳遞資料過大,則會丟擲異常。
頁面標題:
- 目前 ,該引數值會被忽略,暫不被使用,可以傳入空字串。
頁面URL:
- 此引數宣告新添會話記錄的入口URL;
- 在呼叫pushState()方法後,瀏覽器不會載入URL指向的頁面(在重啟瀏覽器後或許會載入新頁面 ),我們可以在popstate事件回撥中處理頁面是否載入;
- 此URL必須與當前頁面URL同源,,否則會拋異常;其值可以是絕對地址,也可以是相對地址,相對地址會被基於當前頁面URL解析 得到絕對地址;若其值為空,則預設是當前頁面URL。
pushState()方法可以改變URL位址列,在會話歷史堆疊頂部插入一條新會話記錄,如:
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");複製程式碼
假如當前訪問頁面blog.codingplayboy.com,則執行以上js程式碼後,瀏覽器位址列變為http://blog.codin…
- 若我們點選瀏覽器的後退按鈕,頁面也不會變化,只是瀏覽器的位址列URL變換為之前的blog.codingplayboy.com;
- 若我們點選跳轉到blog.codingplayboy.com/about.html,…
- 我們可以在popstate事件回撥中執行我們的任務,但是必須知道的是,只有噹噹前頁面DOM載入完成(即DOMContentLoaded事件發生)後才會觸發popstate事件。
- pushState()方法不會觸發hashchange事件,即使URL的hash片段值改變。
replaceState()
與history.pushState()方法相比,history.replaceState()方法不建立新的會話歷史,而是更新當前會話歷史記錄,如更新當前會話記錄的狀態物件或URL。
popstate事件
每次會話記錄變換啟用都會在window上觸發popstate事件,如果啟用的會話記錄是通過replaceState()更新的或使用pushState()方法建立的,popstate事件物件的state屬性值就是該會話記錄狀態物件的一個副本。
location.reload()與location.replace()小結
我們知道location.reload()和location.replace()方法還有直接設定location值,都可以重新載入頁面,但是這三種方式也是有區別的:
reload()
語法
location.reload(beForceGet)
引數
beForceGet,可選,值為true或false;預設為false,表示是否從客戶端快取讀取當前頁;為true時,則從服務端重新請求頁面(相當於F5重新整理和history.go(0)方法)。複製程式碼
replace()
語法
location.replace(url)
引數
一個相對或絕對URL,使用相對於當前頁URL解析後的URL替換當前會話記錄的URL,效果與使用history.replaceState()方法修改URL相同;
對比reload()
location.reload()會取客戶端的快取頁面,但是location.replace(url)總是重新請求載入url指向的頁面。
location賦值
語法
location.href = url;
或
location.assign(url);說明
可以為location直接設定一個URL值,該值等效於使用pushState()修改URL,會建立一條新會話記錄。
攔截使用者返回頁面及強制請求新頁面例項
首先,我們進入首頁index.html,並點選任意跳轉,跳轉到第二頁a.html(當然在實際應用中可以是任意頁面),然後點選返回,我們會發現,並沒有返回到我們訪問的首頁,而是進入了我們設定的攔截頁,具體如何實現的呢,因為我們在第二頁中編寫JavaScript程式碼實現:
;(function() {
window.onpopstate = function(event) {
console.log(event.state);
location.replace('replace.html');
};
history.pushState({name: '驚鴻'}, '', 'a.html?history=1');
})();複製程式碼
我們呼叫pushState()方法建立了一條新會話記錄(該會話URL為a.html?history=1,仔細看瀏覽器位址列變URL變成了a.html?history=1,),並繫結了popstate事件回撥,當瀏覽器返回時,會退回到上一條會話記錄,即a.html會話,然後觸發popstate事件,在事件回撥函式中,我們呼叫location.replace('replace.html')將a.html頁面跳轉至replace.html(可以是任意同源頁面),這就實現了攔截使用者跳轉;隨後,再次點選返回,會返回到我們訪問的第一個頁面,我們檢視NetWork請求會發現不同於之前返回的頁面(請求狀態碼為304),其狀態碼是200,說明是一次新的請求,這是因為在replace.html頁面中,加了如下程式碼:
;(function() {
window.onpopstate= function(event) {
console.log(event.state);
document.location.replace(location.href);
};
})();複製程式碼
我們在popstate事件回撥中,使用location.replace()
方法強制重新整理了當前頁面;當我們在攔截頁點選返回時,會回退到第一頁會話,URL為index.html,然後觸發popstate事件,執行document.location.replace(location.href);
重新整理頁面。
pushState()和replaceState()能做的比我們想象的要多,本文比較詳細的對其進行了介紹,有興趣的同學可以參考MDN或玩w3c,進行更深入的學習,也可以搜尋PJAX,即PushState和Ajax,同時使用這兩個工具,可以極大加快網站響應速度。