引言
最近心氣比較浮躁发皿,潛意識(shí)告訴自己慢一點(diǎn)蛙卤,再慢一點(diǎn),感覺只是說給自己聽的宰翅。
為了緩和一下自己扭曲的心態(tài)弃甥,寫篇博文治療治療~
利用popstate事件和window下的history對象處理瀏覽器跳轉(zhuǎn)
1、popstate事件
當(dāng)活動(dòng)歷史記錄條目更改時(shí)汁讼,將觸發(fā)popstate事件淆攻。如果被激活的歷史記錄條目是通過對history.pushState()的調(diào)用創(chuàng)建的,或者受到對history.replaceState()的調(diào)用的影響嘿架,popstate事件的state屬性包含歷史條目的狀態(tài)對象的副本瓶珊。
需要注意的是調(diào)用history.pushState()或history.replaceState()不會(huì)觸發(fā)popstate事件。只有在做出瀏覽器動(dòng)作時(shí)耸彪,才會(huì)觸發(fā)該事件伞芹,如用戶點(diǎn)擊瀏覽器的回退按鈕(或者在Javascript代碼中調(diào)用history.back())
不同的瀏覽器在加載頁面時(shí)處理popstate事件的形式存在差異。頁面加載時(shí)Chrome和Safari通常會(huì)觸發(fā)(emit )popstate事件蝉娜,但Firefox則不會(huì)唱较。
2、History 接口
屬性:
- History.length 表示歷史會(huì)話中元素的數(shù)目
- History.scrollRestoration 允許Web應(yīng)用程序在歷史導(dǎo)航上顯式地設(shè)置默認(rèn)滾動(dòng)恢復(fù)行為召川。此屬性可以是自動(dòng)的(auto)或者手動(dòng)的(manual)南缓。
- History.state 返回一個(gè)表示歷史堆棧頂部的狀態(tài)的值。這是一種可以不必等待popstate 事件而查看狀態(tài)的方式荧呐。
方法:
- History.back()
等同于history.go(-1)
- History.forward()
等同于history.go(1)
- History.go()
這個(gè)方法中如果參數(shù)超出范圍或者不對就不會(huì)起效果
- History.pushState()
pushState() 帶有三個(gè)參數(shù):一個(gè)狀態(tài)對象汉形,一個(gè)標(biāo)題(現(xiàn)在被忽略了)纸镊,以及一個(gè)可選的URL地址。下面將對這三個(gè)參數(shù)進(jìn)行細(xì)致的檢查
function pushHistory() {
var state = { title: "title", url: "#" };
window.history.pushState(state, "title", "#xx");
}
監(jiān)聽瀏覽器返回按鈕
function pushHistory() {
var state = {
title: "title",
url: "#"
};
window.history.pushState(state, "title", "#xx");
}
pushHistory();
window.addEventListener("popstate", function(e) {
console.log(e);
alert("我監(jiān)聽到了瀏覽器的返回按鈕事件啦");//根據(jù)自己的需求實(shí)現(xiàn)自己的功能
}, false);
這個(gè)地方就監(jiān)聽到了瀏覽器的返回事件概疆,但我有個(gè)疑問逗威,如果不先pushState一個(gè)地址就監(jiān)聽不到,直接跳轉(zhuǎn)了岔冀,這個(gè)暫時(shí)沒搞懂庵楷。
禁止返回上一頁的一種方案
history.pushState(null, null, document.URL);
window.addEventListener("popstate",function(e) {
console.log(e);
history.pushState(null, null, document.URL);
}, false);
這個(gè)其實(shí)就是利用pushState向?yàn)g覽歷史列表中插入當(dāng)前頁面,在點(diǎn)擊后退和前進(jìn)時(shí)都插入一次楣颠,那樣無論點(diǎn)前進(jìn)還是后退永遠(yuǎn)都會(huì)留在這個(gè)頁面了
其他方法就不一一列舉了尽纽,感興趣的看文檔
- History.back()
前往上一頁, 用戶可點(diǎn)擊瀏覽器左上角的返回按鈕模擬此方法. 等價(jià)于 history.go(-1).
Note: 當(dāng)瀏覽器會(huì)話歷史記錄處于第一頁時(shí)調(diào)用此方法沒有效果,而且也不會(huì)報(bào)錯(cuò)童漩。
- History.forward()
在瀏覽器歷史記錄里前往下一頁弄贿,用戶可點(diǎn)擊瀏覽器左上角的前進(jìn)按鈕模擬此方法. 等價(jià)于 history.go(1).
- History.go()
通過當(dāng)前頁面的相對位置從瀏覽器歷史記錄( 會(huì)話記錄 )加載頁面。比如:參數(shù)為-1的時(shí)候?yàn)樯弦豁摻门颍瑓?shù)為1的時(shí)候?yàn)橄乱豁? 當(dāng)整數(shù)參數(shù)超出界限時(shí)( 譯者注:原文為When integerDelta is out of bounds )差凹,例如: 如果當(dāng)前頁為第一頁,前面已經(jīng)沒有頁面了侧馅,我傳參的值為-1危尿,那么這個(gè)方法沒有任何效果也不會(huì)報(bào)錯(cuò)。調(diào)用沒有參數(shù)的 go() 方法或者不是整數(shù)的參數(shù)時(shí)也沒有效果馁痴。( 這點(diǎn)與支持字符串作為url參數(shù)的IE有點(diǎn)不同)谊娇。
- History.pushState()
按指定的名稱和URL(如果提供該參數(shù))將數(shù)據(jù)push進(jìn)會(huì)話歷史棧,數(shù)據(jù)被DOM進(jìn)行不透明處理罗晕;你可以指定任何可以被序列化的javascript對象济欢。
在HTML 文件中, history.pushState()
方法向?yàn)g覽器歷史添加了一個(gè)狀態(tài)。
pushState() 帶有三個(gè)參數(shù):一個(gè)狀態(tài)對象小渊,一個(gè)標(biāo)題(現(xiàn)在被忽略了)法褥,以及一個(gè)可選的URL地址。下面將對這三個(gè)參數(shù)進(jìn)行細(xì)致的檢查:
state object — 狀態(tài)對象是一個(gè)由 pushState()方法創(chuàng)建的酬屉、與歷史紀(jì)錄相關(guān)的JS對象半等。當(dāng)用戶定向到一個(gè)新的狀態(tài)時(shí),會(huì)觸發(fā)popstate事件呐萨。事件的state屬性包含了歷史紀(jì)錄的state對象杀饵。(譯者注:總而言之,它存儲(chǔ)JSON字符串垛吗,可以用在popstate事件中凹髓。)state 對象可以是任何可以序列化的東西。由于 火狐 會(huì)將這些對象存儲(chǔ)在用戶的磁盤上怯屉,所以用戶在重啟瀏覽器之后這些state對象會(huì)恢復(fù)蔚舀,我們施加一個(gè)最大640k 的字符串在state對象的序列化表示上。如果你像pushState() 方法傳遞了一個(gè)序列化表示大于640k 的state對象锨络,這個(gè)方法將扔出一個(gè)異常赌躺。如果你需要更多的空間,推薦使用sessionStorage或者localStorage羡儿。
title — 火狐瀏覽器現(xiàn)在已經(jīng)忽略此參數(shù)礼患,將來也許可能被使用÷庸椋考慮到將來有可能的改變缅叠,傳遞一個(gè)空字符串是安全的做法。當(dāng)然虏冻,你可以傳遞一個(gè)短標(biāo)題給你要轉(zhuǎn)變成的狀態(tài)肤粱。(譯者注:現(xiàn)在大多數(shù)瀏覽器不支持或者忽略這個(gè)參數(shù),最好用null代替)
URL — 這個(gè)參數(shù)提供了新歷史紀(jì)錄的地址厨相。請注意领曼,瀏覽器在調(diào)用pushState()方法后不會(huì)去加載這個(gè)URL,但有可能在之后會(huì)這樣做蛮穿,比如用戶重啟瀏覽器之后庶骄。新的URL不一定要是絕對地址,如果它是相對的践磅,它一定是相對于當(dāng)前的URL单刁。新URL必須和當(dāng)前URL在同一個(gè)源下;否則,pushState() 將丟出異常府适。這個(gè)參數(shù)可選幻碱,如果它沒有被特別標(biāo)注,會(huì)被設(shè)置為文檔的當(dāng)前URL细溅。
- History.replaceState()
按指定的數(shù)據(jù)褥傍,名稱和URL(如果提供該參數(shù)),更新歷史棧上最新的入口喇聊。這個(gè)數(shù)據(jù)被DOM 進(jìn)行了不透明處理恍风。你可以指定任何可以被序列化的javascript對象。
再度強(qiáng)化認(rèn)識(shí)
上面的敘述讓我們對一些基本要素有些認(rèn)識(shí)誓篱,但是實(shí)操下來不盡如人意朋贬,沒有達(dá)到預(yù)期的理解效果。
一窜骄、popstate用來做什么的锦募?
簡而言之就是HTML5新增的用來控制瀏覽器歷史記錄的api。
二邻遏、過去如何操縱瀏覽器歷史記錄糠亩?
window.history對象虐骑,該對象上包含有l(wèi)ength和state的兩個(gè)值,在它的proto上繼承有back赎线、forward廷没、go等幾個(gè)功能函數(shù)
在popstate之前,我們可以利用back垂寥、forward颠黎、go對history進(jìn)行后退和前進(jìn)操作。
例如:
history.back(); (后退一步滞项,使用history.go(-1)也可實(shí)現(xiàn)后退效果)
弊端:只能操作前進(jìn)后退狭归,但是無法控制前進(jìn)后要去哪,history.length都只會(huì)維持原來的狀態(tài)
三文判、popstate的怎么用过椎?
HTML5的新API擴(kuò)展了window.history,使歷史記錄點(diǎn)更加開放了律杠√读鳎可以存儲(chǔ)當(dāng)前歷史記錄點(diǎn)pushState、替換當(dāng)前歷史記錄點(diǎn)replaceState柜去、監(jiān)聽歷史記錄點(diǎn)popstate灰嫉。
pushState、replaceState兩者用法差不多嗓奢。
使用方法:
history.pushState(data,title,url);
//其中第一個(gè)參數(shù)data是給state的值讼撒;
//第二個(gè)參數(shù)title為頁面的標(biāo)題,但當(dāng)前所有瀏覽器都忽略這個(gè)參數(shù)股耽,傳個(gè)空字符串就好根盒;
//第三個(gè)參數(shù)url是你想要去的鏈接;
replaceState用法類似物蝙,例如:history.replaceState("首頁","",location.href+ "#news");
兩者區(qū)別:pushState會(huì)改變history.length炎滞,而replaceState不改變history.length
通過下圖我們可以對比看出pushState和replaceState的差別(注意看history.length的變化):
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>圖解用HTML5的popstate如何玩轉(zhuǎn)瀏覽器歷史記錄</title>
</head>
<body>
<span class="js-news">新聞</span>
<span class="js-music">音樂</span>
<script>
var locationHref = location.href;
document.addEventListener("click", function (event) {
var target = event.target;
if (target.className == "js-news") {
history.pushState("首頁", "", locationHref + "#news");
} else if (target.className == "js-music") {
history.pushState("音樂", "", locationHref + "#music");
}
});
/* document.addEventListener("click",function(event){
var target = event.target;
if(target.className == "js-news"){
history.replaceState("首頁","",locationHref + "#news");
}else if(target.className == "js-music"){
history.replaceState("音樂","",locationHref + "#music");
}
});*/
window.addEventListener("popstate", function () {
console.log(history.state);
})
</script>
</body>
</html>
四、監(jiān)聽瀏覽器狀態(tài)(popstate)變化事件
可以理解為監(jiān)聽瀏覽器后退诬乞、前進(jìn)的操作册赛,只要后退或者前進(jìn)就會(huì)觸發(fā)。在上面的demo中震嫉,我們預(yù)先做了如下操作:打開頁面→點(diǎn)擊“新聞”→點(diǎn)擊“音樂”→再點(diǎn)擊“新聞”森瘪,產(chǎn)生了4個(gè)history記錄。然后監(jiān)聽瀏覽器后退和前進(jìn)的狀態(tài)變化票堵,如下圖所示:
遇到的一些小坑
pushState方法在改變url的同時(shí)向?yàn)g覽器歷史棧中壓入新的歷史記錄扼睬。
接收url的參數(shù)為string類型,用以改變當(dāng)前地址欄的url。需要注意的一點(diǎn)就是這個(gè)參數(shù)不能進(jìn)行跨域悴势,即協(xié)議窗宇,域名措伐,端口必須都是相同的,如果出現(xiàn)跨域的情況担映,即會(huì)提示:
Uncaught DOM Exception: Failed to execute 'pushState' on 'History': A history state object with URL http://www.baidu.com/ cannot be created in a document with origin 'http://commanderXL.com' and URL
Example:
打開www.baidu.com
history.pushState(null, null, '?page=1')
//地址欄變成 www.baidu.com/?page=1
history.pushState(null, null, '#page=2');
//地址欄變成 www.baidu.com/#page=2
其中replaceState:
history.replaceState(null, null, '#page=2');
replaceState
接收的參數(shù)與pushState
相同废士,但是最終的效果是:地址欄url會(huì)根據(jù)接收的參數(shù)而變化叫潦,但是瀏覽器并未在當(dāng)瀏覽歷史棧中增加瀏覽器的歷史記錄蝇完,而是替換當(dāng)前的瀏覽器歷史記錄。