瀏覽器上的window.history就是記錄頁面的歷史記錄的,在瀏覽器上打印history對象,會有如下:
History {pushState: ?, replaceState: ?, length: 7, scrollRestoration: "auto", state: null}
history.length
length是指當(dāng)前瀏覽過多少個頁面,無論你是執(zhí)行后退還是前進(jìn)一頁,history都是不變的,除非在當(dāng)前頁面新打開一個鏈接,那么history就會加一。
history.pushState
history.pushState(State,Title,Url),不跳轉(zhuǎn),新增一條歷史記錄,當(dāng)前頁面的url會變成Url,但是不會刷新當(dāng)前頁面,如果此時新打開一個頁面,后退會去到Url鏈接,但頁面內(nèi)容還是url的內(nèi)容,再后退就會去到url鏈接,內(nèi)容不變,就是url的內(nèi)容。
需要注意的是,history.pushState的Url不能跨域,否則會報錯。
history.replaceState
history..replaceState(State,Title,Url),不跳轉(zhuǎn),修改瀏覽歷史中當(dāng)前紀(jì)錄,當(dāng)前頁面url的歷史記錄會被替換成指定的Url,當(dāng)前頁面的url會變成Url,直接替換掉原來的url,相當(dāng)于原來的url已經(jīng)不存在,但是不會刷新當(dāng)前頁面,如果此時新打開一個頁面,后退會去到Url鏈接,但頁面內(nèi)容會改變成Url的內(nèi)容,再后退就沒有可后退的鏈接了。
需要注意的是,history.replaceState的Url不能跨域,否則會報錯。
location.replace
location.replace(url) 會跳轉(zhuǎn)至指定頁面,當(dāng)前頁面url的歷史記錄不會保留,相當(dāng)于替換了當(dāng)前的歷史記錄
location.href
location.href:跳轉(zhuǎn)至指定頁面,當(dāng)前頁面url的歷史記錄會保留
window.onpopstate
每當(dāng)同一個文檔的瀏覽歷史(即history對象)出現(xiàn)變化時,就會觸發(fā)popstate事件。僅僅調(diào)用pushState方法或replaceState方法 ,并不會觸發(fā)該事件,只有用戶點擊瀏覽器倒退按鈕和前進(jìn)按鈕,或者使用JavaScript調(diào)用back、forward、go方法時才會觸發(fā)。使用的時候,可以為popstate事件指定回調(diào)函數(shù)。這個回調(diào)函數(shù)的參數(shù)是一個event事件對象,它的state屬性指向pushState和replaceState方法為當(dāng)前URL所提供的狀態(tài)對象(即這兩個方法的第一個參數(shù)state)。如:
history.pushState({title:"login"}, "login", "/login");
window.onpopstate = function (event) {
if(event.state) {
var state = event.state.title;
switch(state) {
case "login":.............;break;
case "join" :.............;break;
}
}
};
// 或者
window.addEventListener("popstate", function(event){
if(event.state) {
var state = event.state.title;
switch(state) {
case "login":.............;break;
case "join" :.............;break;
}
}
}, false);
上面代碼中的event.state,就是通過pushState和replaceState方法,為當(dāng)前URL綁定的state對象。這個state對象也可以直接通過history對象讀取history.state。
實踐
最近做的一個需求是這樣的:先由中轉(zhuǎn)頁a跳去目標(biāo)頁面b,按回退按鈕,跳去中間后臺配置頁面b1,再按回退按鈕跳去中間后臺配置頁面b2,以此下去,只到跳轉(zhuǎn)完所有后臺配置的頁面,最終跳回目標(biāo)頁面b,再按返回退出所有頁面。
用history來解釋的話就是:
a->b->back->a->b1->back->b2->...->back->b->back->退出
用上面的知識來解決就是
a->b,在a頁面,獲取跳轉(zhuǎn)url的b頁面鏈接,替換參數(shù),改變a鏈接成a*,即將a的歷史記錄修改成a*,執(zhí)行
history.replaceState(null, document.title, a*);window.location.href = b;
回退,此時到a*,獲取后臺配置,執(zhí)行
window.location.href = b1;
回退,此時到a*,獲取后臺配置,執(zhí)行
window.location.href = b2;
....
后退回到a*,最后回到b,執(zhí)行
window.location.replace(b);
再后退,退出頁面
以上就是利用history和location解決的一個簡單示例,其他的應(yīng)用還可以是改變一個頁面的url而不用刷新頁面等。
外篇
pageshow 和 pagehide 事件
手機(jī)上的瀏覽器有一個特性,名叫“往返緩存”(back-forward cache,或bfcache),可以在用戶使用瀏覽器的“后退”和“前進(jìn)”按鈕時加快頁面的轉(zhuǎn)換速度。這個緩存中不僅保存著頁面數(shù)據(jù),還保存了DOM和JavaScript的狀態(tài);實際上是將整個頁面都保存在了內(nèi)存里。如果頁面位于bfcache中,那么再次打開該頁面就不會觸發(fā)load事件。盡管由于內(nèi)存中保存了整個頁面的狀態(tài),不觸發(fā)load事件也不應(yīng)該會導(dǎo)致什么問題,但為了更形象地說明bfcache的行為,F(xiàn)irefox還是提供了一些新事件。 第一個事件就是pageshow,這個事件在頁面顯示時觸發(fā),無論頁面是否來自bfcache。在重新加載頁面中,pageshow會在load事件觸發(fā)后觸發(fā);而對于bfcache中的頁面,pageshow會在頁面狀態(tài)完全恢復(fù)的那一刻觸發(fā)。
1)load 和 unload 事件監(jiān)聽web頁面的進(jìn)入和離開,一般用于頁面的首次加載、刷新和關(guān)閉等操作的監(jiān)聽;
2)pageshow 和 pagehide 事件多用于監(jiān)聽瀏覽器的前進(jìn)和后退等。
pageshow和load區(qū)別:
pageshow 事件類似于 load 事件,load 事件在頁面第一次加載時觸發(fā), pageshow 事件在每次加載頁面時觸發(fā),即 load 事件在頁面從瀏覽器緩存中讀取時不觸發(fā)。
一般情況下,移動端瀏覽器會將當(dāng)前已訪問頁面存入緩存中,緩存中保存著頁面數(shù)據(jù),DOM和js的狀態(tài),前進(jìn)和后退操作時直接從瀏覽器緩存中讀取頁面內(nèi)容,而不進(jìn)行頁面刷新,所以監(jiān)聽前進(jìn)和后退操作時可用pageshow事件。
window.performance對象
performance.navigation.type是一個無符號短整型,接口呈現(xiàn)了如何導(dǎo)航到當(dāng)前文檔的信息。它有四種type類型:
1、TYPE_NAVIGATE (0):當(dāng)前頁面是通過點擊鏈接,書簽和表單提交,或者腳本操作,或者在url中直接輸入地址,type值為0。
2、TYPE_RELOAD (1):點擊刷新頁面按鈕或者通過Location.reload()方法顯示的頁面,type值為1:。
3、TYPE_BACK_FORWARD (2):頁面通過歷史記錄和前進(jìn)后退訪問時。type值為2。
4、TYPE_RESERVED (255): 任何其他方式,type值為255。
所以type為2可以作為頁面后退或者前進(jìn)時的一個判斷依據(jù)。
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type == 2)) {
// 頁面后退或者前進(jìn)時刷新頁面
location.reload()
}