HTML5中history提供的pushState
, replaceState這兩個
API。它們提供了操作瀏覽器歷史棧的方法。
pushState能夠在不載入頁面的情況下改變瀏覽器的URL。這個方法接受三個引數:
狀態物件,新狀態的標題和可選的相對URL。
history.pushState(data, null, '#/page=1');
pushState接收3個引數,第一個引數為一個obj,表示瀏覽器的state屬性;
第二個引數是document.title的值,一般設定為`null`;
第三個引數string,用以改變當前url;
pushState
方法在改變url
的同時向瀏覽器歷史棧中壓入新的歷史記錄。
接收url
的引數為string
型別,用以改變當前位址列的url.需要注意的一點就是這個引數不能和跨域,即協議,域名,埠必須都是相同的,如果出現跨域的情況,即會提示:
Example:
其中 replaceState:
replaceState
接收的引數pushState
相同,但是最終的效果是:位址列url會根據接收的引數而變化,但是瀏覽器並未在當瀏覽歷史棧中增加瀏覽器的歷史記錄,而是替換當前的瀏覽器歷史記錄。
通過pushState
和replaceState
雖然能改變URL,但是不會主動觸發瀏覽器reload
。
window
物件還提供 popstate
方法 :
這個方法用以監聽瀏覽器在不同歷史記錄中進行切換,而觸發相應的事件。
在瀏覽器提供的history物件上還有go
, back
方法,用以模擬使用者點選瀏覽器的前進後退按鈕。在某個web應用當中,比如點選了<a>
標籤,發生了頁面的跳轉。這時呼叫history.back()
方法後頁面回退,同時頁面發生重新整理,這時window.onpopstate
無法監聽這個事件。但是如果是通過pushState
或者replaceState
來改變URL且不發生瀏覽器重新整理的話,再使用history.back()
或history.go()
,這樣popstate
事件會被觸發。
輸出如下:
注意: 通過pushState
在url上新增?page=1
可以通過location.search
去獲取search
的內容。不過如果通過location.search
去改變url
的話是會主動觸發瀏覽器reload
的。
API大致瞭解了,那麼這些方法可以運用到哪些地方呢?一個比較常用的場景是就在單頁應用中,通過這些API完成前端的路由設計,利用pushState
, replaceState
可以改變url
同時瀏覽器不重新整理,並且通過 popstate
監聽瀏覽器歷史記錄的方式,完成一系列的非同步動作。
簡單的路由如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> a {color: red;text-decoration: underline;} </style> </head> <body> <a data-href="/post">post</a> <a data-href="/login">login</a> <script> const Router = []; const addRoute = (path ='', handle=() =>{}) => { let obj = { path, handle }; Router.push(obj); } // 新增路由定義 addRoute('/post', function(){ // todo... alert('/post'); }) addRoute('/login', function(){ // todo... alert('login'); }) // 路由處理 const routeHandle = (path) => { for(var item of Router){ if (item.path === path) { item.handle.apply(null, [path]); return true; } } } document.addEventListener('click', function(e) { let dataset = e.target.dataset; if(dataset) { if(routeHandle(dataset.href)) { var url = window.location.href; history.pushState({route: dataset.href}, null, oriUrl + dataset.href); //阻止預設行為 return false; // e.preventDefault(); } } }) </script> </body> </html>
大致的實現思路就是,通過<a>
新增路由資訊,然後攔截<a>
標籤的預設行為,並與註冊的路由資訊進行匹配。若匹配成功呼叫對應的handle
方法。