前端路由的實現(三) —— History的pushState和replaceState用法
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
方法。
前端路由的實現(三) —— History的pushState和replaceState用法