javascript
JavaScript hash 与 history 实现客户端路由的原理
客戶端路由有兩種實現方式:基于hash 和基于html5 history api。
vue-router 組件就是基于它們來實現的。
vue-router 組件中的路由涉及到了三個基本的概念: route, routes, router。
回到 H5 的 history 上來。
history 可以通過參數來保存用戶的操作,并且無需刷新就可以在頁面間進行切換。常見于單頁面應用(SPA,Simple Page Application)框架里。
window.history 對象在編寫時可不使用 window 這個前綴。
- history.back()
加載歷史列表中的上一個 URL,與瀏覽器點擊后退按鈕作用相同。等價于history.go(-1)。
返回上一頁時,頁面通常是從瀏覽器緩存之中加載,而不是重新要求服務器發送新的網頁。 - history.forward()
加載歷史列表中的下一個 URL,與瀏覽器點擊向前按鈕作用相同。等價于history.go(-1)。 - history.go(int n)
移動到該整數指定的頁面,比如go(1)相當于forward(),go(-1)相當于back(),history.go(0)相當于刷新當前頁面。
如果移動的位置超出了訪問歷史的邊界,以上三個方法并不報錯,而是默默的失敗。
-
history.scrollRestoration
設置滾動恢復行為。通俗的來講就是,當我們從當前頁面跳轉到a頁面,隨后又從a頁面回退過來的時候,我們的頁面是否應該自動滾動到我們之前瀏覽的位置。
scrollRestoration默認值是auto,默認滾動恢復。另外一個值是manual,表示不會默認恢復 -
window.location
對象用于獲得當前頁面的地址 (URL),或將瀏覽器重定向到新的頁面。- location.hash 設置或返回從井號 (#) 開始的 URL(錨)
- location.host 設置或返回主機名和當前 URL 的端口號
- location.hostname 設置或返回當前 URL 的主機名
- location.href 屬性返回當前頁面的 URL
- location.pathname 設置或返回當前 URL 的路徑部分
- location.port 設置或返回當前 URL 的端口號
- location.protocol 設置或返回當前 URL 的協議(http:// 或 https://)
- search 設置或返回從問號 (?) 開始的 URL(查詢部分)
- location.assign(url) 加載新的文檔
- location.reload() 重新加載當前文檔
- location.replace(url) 加載新的文檔,在歷史列表中,新文檔會替換當前文檔
HTML5為history對象添加了兩個新方法,history.pushState()和history.replaceState(),用來在瀏覽歷史中添加和修改記錄。
- history.pushState(state, title, url)
調用該方法后,瀏覽器只會替換地址欄地址,并且推入歷史列表,但并不會刷新頁面。- state 存儲數據的對象,瀏覽器會自動序列化。最大存儲空間為640k,超過這個值會拋出錯誤。當瀏覽器地址改變,且處于同一域的時候,會觸發popstate事件,該事件的參數event.state即為本對象。
- title 設置標題(所有瀏覽器均不支持)
- url 地址欄替換成新的URL(在firefox下測試發現,url只支持相對地址,且必須在該域名下面;如果原地址已html結尾,那么只能加#)
在本地測試的時候,大家可能會遇到如下問題: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)
?
翻譯如下:
請確認你遵守了同源策略。它意味著相同的域名,相同的子域名,相同的協議(http 和 https)和端口。
那么 pushState 如何防止潛在的內容偽造呢?
正如某人在他的評論中指出的,一些瀏覽器對于源是 file:/// 的實現稍有不同。這并不意味著當你在本地測試 來自不同源的 file:/// 的時候會遭遇困難(因此你可以在生產腳本上測試pushState,而非本地腳本)
最佳回答說了一堆廢話。簡而言之就是 pushState只適用于http 和 https協議,而對于 file 協議僅能采用錨點,其他都違反了安全策略
-
history.replaceState(state, title, url)
replaceState和pushState的參數一摸一樣,功能也差不多。
唯一的區別是:pushState()是在history棧中添加一個新的條目,replaceState()是替換當前的記錄值。 -
window.addEventListener(“popstate”, (event)=>{})
history 實體改變時觸發的事件。通過在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>總結
以上是生活随笔為你收集整理的JavaScript hash 与 history 实现客户端路由的原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一次竞选博客之星,第一次阳光普照
- 下一篇: 支付宝实现JS调起支付你必须知道的坑(4