javascript
JavaScript hash 与 history 实现客户端路由的原理
客戶端路由有兩種實(shí)現(xiàn)方式:基于hash 和基于html5 history api。
vue-router 組件就是基于它們來實(shí)現(xiàn)的。
vue-router 組件中的路由涉及到了三個(gè)基本的概念: route, routes, router。
回到 H5 的 history 上來。
history 可以通過參數(shù)來保存用戶的操作,并且無需刷新就可以在頁面間進(jìn)行切換。常見于單頁面應(yīng)用(SPA,Simple Page Application)框架里。
window.history 對象在編寫時(shí)可不使用 window 這個(gè)前綴。
- history.back()
加載歷史列表中的上一個(gè) URL,與瀏覽器點(diǎn)擊后退按鈕作用相同。等價(jià)于history.go(-1)。
返回上一頁時(shí),頁面通常是從瀏覽器緩存之中加載,而不是重新要求服務(wù)器發(fā)送新的網(wǎng)頁。 - history.forward()
加載歷史列表中的下一個(gè) URL,與瀏覽器點(diǎn)擊向前按鈕作用相同。等價(jià)于history.go(-1)。 - history.go(int n)
移動到該整數(shù)指定的頁面,比如go(1)相當(dāng)于forward(),go(-1)相當(dāng)于back(),history.go(0)相當(dāng)于刷新當(dāng)前頁面。
如果移動的位置超出了訪問歷史的邊界,以上三個(gè)方法并不報(bào)錯(cuò),而是默默的失敗。
-
history.scrollRestoration
設(shè)置滾動恢復(fù)行為。通俗的來講就是,當(dāng)我們從當(dāng)前頁面跳轉(zhuǎn)到a頁面,隨后又從a頁面回退過來的時(shí)候,我們的頁面是否應(yīng)該自動滾動到我們之前瀏覽的位置。
scrollRestoration默認(rèn)值是auto,默認(rèn)滾動恢復(fù)。另外一個(gè)值是manual,表示不會默認(rèn)恢復(fù) -
window.location
對象用于獲得當(dāng)前頁面的地址 (URL),或?qū)g覽器重定向到新的頁面。- location.hash 設(shè)置或返回從井號 (#) 開始的 URL(錨)
- location.host 設(shè)置或返回主機(jī)名和當(dāng)前 URL 的端口號
- location.hostname 設(shè)置或返回當(dāng)前 URL 的主機(jī)名
- location.href 屬性返回當(dāng)前頁面的 URL
- location.pathname 設(shè)置或返回當(dāng)前 URL 的路徑部分
- location.port 設(shè)置或返回當(dāng)前 URL 的端口號
- location.protocol 設(shè)置或返回當(dāng)前 URL 的協(xié)議(http:// 或 https://)
- search 設(shè)置或返回從問號 (?) 開始的 URL(查詢部分)
- location.assign(url) 加載新的文檔
- location.reload() 重新加載當(dāng)前文檔
- location.replace(url) 加載新的文檔,在歷史列表中,新文檔會替換當(dāng)前文檔
HTML5為history對象添加了兩個(gè)新方法,history.pushState()和history.replaceState(),用來在瀏覽歷史中添加和修改記錄。
- history.pushState(state, title, url)
調(diào)用該方法后,瀏覽器只會替換地址欄地址,并且推入歷史列表,但并不會刷新頁面。- state 存儲數(shù)據(jù)的對象,瀏覽器會自動序列化。最大存儲空間為640k,超過這個(gè)值會拋出錯(cuò)誤。當(dāng)瀏覽器地址改變,且處于同一域的時(shí)候,會觸發(fā)popstate事件,該事件的參數(shù)event.state即為本對象。
- title 設(shè)置標(biāo)題(所有瀏覽器均不支持)
- url 地址欄替換成新的URL(在firefox下測試發(fā)現(xiàn),url只支持相對地址,且必須在該域名下面;如果原地址已html結(jié)尾,那么只能加#)
在本地測試的時(shí)候,大家可能會遇到如下問題:SecurityError: The operation is insecure.
?
https://stackoverflow.com/questions/13348766/securityerror-the-operation-is-insecure-window-history-pushstate
?
Make sure you are following the Same Origin Policy. This means same domain, same subdomain, same protocol (http vs https) and same port.
?
How does pushState protect against potential content forgeries?
?
As @robertc aptly pointed out in his comment, some browsers actually implement slightly different security policies when the origin is file:///. Not to mention you can encounter problems when testing locally with file:/// when the page expects it is running from a different origin (and so your pushState assumes production origin scenarios, not localhost scenarios)
?
翻譯如下:
請確認(rèn)你遵守了同源策略。它意味著相同的域名,相同的子域名,相同的協(xié)議(http 和 https)和端口。
那么 pushState 如何防止?jié)撛诘膬?nèi)容偽造呢?
正如某人在他的評論中指出的,一些瀏覽器對于源是 file:/// 的實(shí)現(xiàn)稍有不同。這并不意味著當(dāng)你在本地測試 來自不同源的 file:/// 的時(shí)候會遭遇困難(因此你可以在生產(chǎn)腳本上測試pushState,而非本地腳本)
最佳回答說了一堆廢話。簡而言之就是 pushState只適用于http 和 https協(xié)議,而對于 file 協(xié)議僅能采用錨點(diǎn),其他都違反了安全策略
-
history.replaceState(state, title, url)
replaceState和pushState的參數(shù)一摸一樣,功能也差不多。
唯一的區(qū)別是:pushState()是在history棧中添加一個(gè)新的條目,replaceState()是替換當(dāng)前的記錄值。 -
window.addEventListener(“popstate”, (event)=>{})
history 實(shí)體改變時(shí)觸發(fā)的事件。通過在popstate()事件中添加pushState()方法,可以讓用戶無法后退,且頁面不會刷新
測試代碼如下
<!DOCTYPE html> <html> <head> <meta charset="utf8"> <script> function objToStr(obj) {let desc = ""; for(let i in obj){ let property = obj[i]; desc += i + " = " + property + "<br>"; }return desc; } function init() {document.getElementById("number").value = -1;const locationElem = document.getElementById("location");locationElem.innerHTML = "location: <br>" + objToStr(location);const historyElem = document.getElementById("history");historyElem.innerHTML = "history: <br>" + objToStr(history);window.addEventListener("popstate", (event)=>{console.log(event);//通過在popstate添加pushState方法,可以讓用戶無法后退,且頁面不會刷新//pushState();}, false); } function pushState() {var state = {title: "title",url: "#history"};window.history.pushState(state, state.title, state.url); } </script> </head> <body "init()"> <button onclick="javascript:history.forward()">forward</button> <button onclick="javascript:history.back()">back</button> <div> <input type="number" id="number"/><button onclick="javascript:history.go(document.getElementById('number').value)">go</button> </div> <!-- history: go = function go() { [native code] } back = function back() { [native code] } forward = function forward() { [native code] } pushState = function pushState() { [native code] } replaceState = function replaceState() { [native code] } length = 3 scrollRestoration = auto state = null --> <p id="history"></p><button onclick="javascript:location='http://www.baidu.com'">relocate</button> <!-- location: href = file:///D:/node/test20181018/public/history.html origin = null protocol = file: host = hostname = port = pathname = /D:/node/test20181018/public/history.html search = hash = assign = function assign() { [native code] } replace = function replace() { [native code] } reload = function reload() { [native code] } toString = function toString() { [native code] } --> <p id="location"></p> <button onclick="pushState()">pushState</button> </body> </html>總結(jié)
以上是生活随笔為你收集整理的JavaScript hash 与 history 实现客户端路由的原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一次竞选博客之星,第一次阳光普照
- 下一篇: 支付宝实现JS调起支付你必须知道的坑(4