前端路由實現原理(history)

前端路由實現(history)

瞭解:

HTML5 history新增了兩個API:history.pushState和history.replaceStatejavascript

兩個api都接受三個參數

  • 狀態對象(state object):一個JavaScript對象,與用pushState()方法建立的新歷史記錄條目關聯。不管什麼時候用戶導航到新建立的狀態,popstate事件都會被觸發,而且事件對象的state屬性都包含歷史記錄條目的狀態對象的拷貝。css

  • 標題(title):FireFox瀏覽器目前會忽略該參數,雖然之後可能會用上。考慮到將來可能會對該方法進行修改,傳一個空字符串會比較安全。或者,你也能夠傳入一個簡短的標題,標明將要進入的狀態。html

  • 地址(URL): 新的歷史記錄條目的地址。瀏覽器不會在調用pushState()方法後加載該地址,但以後,可能會試圖加載,例如用戶重啓瀏覽器。新的URL不必定是絕對路徑;若是是相對路徑,它將以當前URL爲基準;傳入的URL與當前URL應該是同源的,不然,pushState()會拋出異常。該參數是可選的;不指定的話則爲文檔當前URL。前端

相同之處是兩個API都會操做瀏覽器的歷史記錄,而不會引發頁面的刷新。不一樣之處在於pushState會增長一條新的歷史記錄,而replaceState則會替換當前的歷史記錄java

你們能夠先在控制檯試試,看看地址欄發生了什麼變化

window.history.pushState(null, null, "test");

window.history.pushState(null, null, "/test");

window.history.pushState(null, null, "#/hello");

window.history.pushState(null, null, "?name=");
</code></pre>
複製代碼

實例演示

創建html文件,index.htmljquery

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>前端路由實現</title>
    <style>
        .warp{
            width:400px;
            height:400px;
            border:1px solid grey;
            margin:0 auto;
        }
        .nav{
            border-bottom:1px solid grey;
        }
        .nav li{
            display:inline-block;
            list-style:none;
        }
        .nav li a{
            display:inline-block;
            text-decoration: none;
            padding:10px 15px;
        }
        .router{
            padding:20px;
        }
        a{
            cursor: pointer;
        }
    </style>

</head>
<body>
    <section class="warp">
        <div class="nav">          
            <ul>
                <li><a href="javascript:void(0)" data-path="index">首頁</a></li> 
                <li><a href="javascript:void(0)" data-path="news">新聞</a></li>
                <li><a href="javascript:void(0)" data-path="about">關於</a></li>
            </ul>
        </div>
        <div id="router" class="router">
            <!-- 內容加載區域 -->
        </div>
    </section>

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="./router.js"></script>

</body>
</html>
複製代碼

此時的頁面爲:api

引入js文件router.js瀏覽器

(function(){   
  history.replaceState(null,null,'');//最開始的狀態,採用replace直接替換
  $('#router').html('<p>顯示內容區域</p>')
  $('a').on('click',function(){
      console.log(this.text)
      var text = this.text;
      $('#router').html('<p>'+ text +'</p>')
      history.pushState(null,null,'#/'+text);
  })    
})()
複製代碼

此時點擊導航按鈕時安全

  • 此時當點擊不一樣的導航項的時候,地址欄上的路由進行了對應的改變,展示的內容區域也發生了變化。可是實際上這個並無實現路由的真正含義。由於內容部分的改變是根據事件的觸發而得到當前的內容。
  • 此時若是點擊瀏覽的前進和後退按鈕,內容是沒法監聽到地址欄的變化而做出改變的

在此基礎上變更一下實現方式,將router.js改成:

// 狀態版
(function(){   
   var count = [0,0,0]
   $('#router').html('<p>首頁</p>'+count[0]+'<p>新聞</p>'+count[1]+'<p>關於</p>'+count[2])
   // history.replaceState(count,null,'');//最開始的狀態,採用replace直接替換

   for(var i = 0 ; i<$('a').length; i++){
       $('a')[i].index = i
       $('a').eq(i).on('click',function(){
           console.log(this.index);
           var index = this.index;
           count[index]++;
           $('#router').html('<p>首頁</p>'+count[0]+'<p>新聞</p>'+count[1]+'<p>關於</p>'+count[2])
           console.log(count)
           history.pushState(count,null,'#/count'+count[index]);//以後的狀態,須要進行保存
       })
   }
   //監聽history其餘api致使地址欄url改變事件
   window.addEventListener('popstate',function(e){
       console.log(e.state);
       var state = e.state;
       $('#router').html('<p>首頁</p>'+state[0]+'<p>新聞</p>'+state[1]+'<p>關於</p>'+state[2])

   })
})()
複製代碼

此時的思路是作一個狀態記錄,記錄下每一個導航按鈕被點擊的次數。當每次執行點擊導航欄切換的時候,經過history.pushState(count, null, '#/count'+count[index])這個api,傳遞了狀態對象在內,並在第三個參數中將當前已點擊數做爲地址欄的顯示數據。示例以下:ui

  • !!當活動歷史記錄條目更改時,將觸發popstate事件。若是被激活的歷史記錄條目是經過對history.pushState()的調用建立的,或者受到對history.replaceState()的調用的影響,popstate事件的state屬性包含歷史條目的狀態對象的副本。
  • 須要注意的是調用history.pushState()或history.replaceState()不會觸發popstate事件。只有在作出瀏覽器動做時,纔會觸發該事件,如用戶點擊瀏覽器的回退按鈕(或者在Javascript代碼中調用history.back())

此處經過記錄下每次的點擊次數來解釋了pushState的用法以及參數,其實簡單的寫法能夠表達爲:

(function(){   

    var url = '內容展現';

    history.replaceState(url,null,'');//最開始的狀態,採用replace直接替換
    $('#router').html('<p>'+url+'</p>')

    $('a').on('click',function(){
        console.log(this.text)
        url = this.text;

        $('#router').html('<p>'+ url +'</p>')
        history.pushState(url,null,'#/'+url);
    })
    window.addEventListener('popstate',function(e){
        console.log(e.state);
        url = e.state
        $('#router').html('<p>'+ url +'</p>')

     });     
})()
複製代碼

如今的效果看上去其實咱們至關於回到了遠點,可是解決了沒法監聽地址欄的地址變化問題,是經過監聽popstate來做出響應的。

如今還只是看了這一部分的路由實現機制,要經過監聽做出不一樣的響應。還須要更深刻的與hash進行對比。

相關文章
相關標籤/搜索