簡介 History對象最初設計用來表示視窗的瀏覽歷史,但是,出於隱私方面的原因,History對象不再允許腳本訪問已經訪問過的實際URL。雖然,我們不清楚歷史URL,但是,我們可以通過History對象的內置屬性方法進行跳轉。 對象屬性 length 該屬性代表著瀏覽器歷史列表中的URL數量。初始 ...
簡介
History對象最初設計用來表示視窗的瀏覽歷史,但是,出於隱私方面的原因,History對象不再允許腳本訪問已經訪問過的實際URL。雖然,我們不清楚歷史URL,但是,我們可以通過History對象的內置屬性方法進行跳轉。
對象屬性
length
該屬性代表著瀏覽器歷史列表中的URL數量。初始值為1,如果當前視窗先後訪問了兩個網址,那該屬性的值變為2。
history.length // 1
// 訪問了一個新的URL
history.length // 2
state
HTML5新增屬性,返回一個表示歷史堆棧頂部的狀態的值,這是一種可以不必等待popstate
事件而查看狀態的方式。
scrollRestoration
允許Web應用程式在歷史導航上顯式地設置預設滾動恢復行為。此屬性可以是自動的(auto)或者手動的(manual)。
對象方法
go方法
go
方法是History對象三個方法中的核心方法,通過go
方法可以完美替代其他的兩個方法。該方法接收一個可選參數,這個參數可以是number
也可以是URL
。
ps:經過多次試驗,傳入URL
參數貌似沒有作用,有待後續研究
當使用number
參數時,頁面會跳轉到History的URL列表的相對位置。比如當傳入參數為-1
,則相當於點擊瀏覽器後退按鈕的效果;當傳入參數為1
時,相當於點擊瀏覽器前進按鈕;當不傳參數或者傳入參數為0
時,頁面會刷新。
window.history.go(-1) // 後退
window.history.go(1) // 前進
window.history.go(0) // 刷新
window.history.go() // 刷新
tips:當傳入的number
對應的位置沒有URL,則該條語句會靜默失敗
forward方法
forward
方法可以載入歷史列表中的下一個URL,類似於go(1)
,實現了點擊瀏覽器前進按鈕的效果。
window.history.forward() // 前進
window.history.go(1) // 前進
back方法
back
方法可以載入歷史列表中的上一個URL,類似於go(-1)
,實現了點擊瀏覽器後退按鈕的效果。
window.history.back() // 後退
window.history.go(-1) // 後退
tips:當URL隊列中沒有上一個URL時,back
方法會失效;同理,當URL隊列中沒有下一個URL時,forward
方法會失效。
HTML5新增方法
HTML5為History對象添加了兩個新方法,pushState
和replaceState
方法,用來在瀏覽歷史中添加和修改記錄。
pushState方法
pushState
方法接收三個參數:
- state:一個與指定網址相關的狀態對象,
popstate
事件觸發時,該對象會傳入回調函數。如果不需要這個對象(即不需要傳參),可以設為null
- title:新頁面的標題,但是大部分瀏覽器目前都忽略這個值,所以這裡也可以設為
null
- url:新的網址,必須與當前頁處在同一域,瀏覽器的地址欄將顯示這個網址
比如當前的網址是localhost:63342/1.html
,使用pushState
方法在瀏覽記錄中可以添加一條新的記錄:
window.history.pushState({params: 'aaa'}, null, '2.html')
輸入這行語句後,瀏覽器地址欄中的URL變為了localhost:63342/2.html
,但是無論這是不是一個真實網址,它都不會跳轉,這隻是一條歷史記錄。此時,可以通過state
取到狀態。
此時,如果你前往下個地址後點擊後退按鈕,頁面將返回到localhost:63342/2.html
,此時,也可以通過state
屬性取到狀態。
window.history.state // {params: "aaa"}
tips:如果pushState
的第三個參數是一個跨域網址,控制台會報錯,這主要是因為安全問題,防止不法分子偽裝URL
window.history.pushState(null, null, 'www.baidu.com') // 報錯
replaceState方法
該方法基本和pushState
一致,但是不同的是,該方法會直接替換當前的歷史記錄。
路由插件的原理
傳統的History用法是操縱瀏覽器進行前進或後退的跳轉,用處不是很大。但是,HTML5新增的方法為其帶來了脫胎換骨的變化。
眾所周知,vue-router等一眾路由插件實現的功能是更新頁面的視圖,但是卻不重新請求頁面,也就是說,其實,他們並沒有實際進行了跳轉,而是修改了頁面的DOM並通過修改頁面的URL來模擬跳轉。
在HTML5之前,頁面路由只有hash模式,而HTML5中History對象的新增方法,帶來了另一種模式:history模式。
hash模式
在HTML5之前,vue-router是通過修改URL的hash
值(URL中#
開始的字元串,不瞭解的同學可以看我的上一篇文章)來達到修改頁面URL並生成歷史記錄,但卻不會重新請求頁面。所以,不使用vue-router中history
模式的情況下,你會發現你的路徑前總會有一個#
。
比如,你在vue-router中設置的路徑是/b
,在你的想象中,路徑應該是http://localhost:8080/b
,但是,現實很骨感,實際路徑是:http://localhost:8080/#/b
,原因就是因為沒開啟history
模式的情況下,vue-router是通過hashchange
事件來監聽URL中hash的改變並通過修改hash來模擬路徑的變化。
由於通過window.location.hash
修改hash是會有歷史記錄產生的,所以,在SPA中,依然可以通過後退、前進按鈕來控制路由的跳轉。
hash模式最大的優點是相容性強,可以相容一眾老式瀏覽器。而它最大的缺點是,頁面URL中一直掛著一個難看的#
,這一點連vue-router的官網也對其進行了吐槽。
有需求就有功能,所以,當HTML5發佈後,又有了history模式。
history模式
看到這裡,如果認真看了pushState
方法的同學應該已經差不多明白了,vue-router的history模式就是通過HTML5中History對象的pushState
方法進行模擬的。
當vue-router每次需要跳轉頁面時,頁面DOM的修改方式和時機並沒有改變,和hash模式一樣。但是,修改URL的方式改變了。此時,有了pushState
方法,可以不用修改醜陋的hash模擬而是直接在歷史記錄中添加一條新的URL。
那麼,沒有了hash,如何監聽URL的改變呢?HTML5還提供了一個popstate
事件,當用戶點擊前進、後退按鈕,或者調用back
、forward
、go
方法時觸發,可以監聽URL的改變。
在這裡提一句,使用history模式,就連路由傳值都有更好的方式——使用pushState
的第一個參數進行傳值,使用History的state
屬性進行取值。
當使用了history模式時,使用vue-router跳入/b
時,此時的頁面URL不是醜陋的http://localhost:8080/#/b
,而是預料之中的http://localhost:8080/b
。
// hash模式
window.location.href // http://localhost:8080/#/b
// history
window.location.href // http://localhost:8080/b
總結
雖然,history模式提供了完美的URL顯示,但是,正所謂魚和熊掌不可兼得,相容性和美觀也不可兼得。只有相容了HTML5的瀏覽器(IE10+)才能使用history模式,不然,就老實的繼續使用hash模式吧。
所以,使用何種模式,還是取決於軟體的相容性,如果不需要相容低級瀏覽器,那就放心大膽的使用history模式吧!