1. 程式人生 > >前端路由的實現(三) —— History的pushState和replaceState用法

前端路由的實現(三) —— History的pushState和replaceState用法

最終 標簽 -c 歷史記錄 htm 操作 har PE 能夠

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會根據接收的參數而變化,但是瀏覽器並未在當瀏覽歷史棧中增加瀏覽器的歷史記錄,而是替換當前的瀏覽器歷史記錄。

通過pushStatereplaceState雖然能改變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用法