vue-router ——前端路由實現原理


一、什么是前端路由?

  前端路由是直接找到與地址匹配的一個組件或對象並將其渲染出來。也就是說,通過改變瀏覽器地址URL,在不重新請求頁面的情況下,更新頁面視圖

二、單頁應用與多頁應用

  • 單頁應用

    • 即 第一次進入頁面的時候會請求一個html文件,刷新清除一下。切換到其他組件,此時路徑也相應變化,但是並沒有新的html文件請求,頁面內容也變化了。

    • 原理:JS會感知到url的變化,通過這一點,可以用js動態的將當前頁面的內容清除掉,然后將下一個頁面的內容掛載到當前頁面上,這個時候的路由不是后端來做了,而是前端來做,判斷頁面到底是顯示哪個組件,清除不需要的,顯示需要的組件。這種過程就是單頁應用,每次跳轉的時候不需要再請求html文件了

  • 多頁應用

    • 每一次頁面跳轉的時候,后台服務器都會給返回一個新的html文檔,這種類型的網站也就是多頁網站,也叫做多頁應用。

    • 原理:用一些超鏈接來實現頁面切換和跳轉的

  • 參考:https://www.jianshu.com/p/4c9c29967dd6

三、實現方式

·  vue-router 提供了三種模式來實現前端路由:1.hash模式 2.history模式 3.abstract模式。hash模式與history模式,這兩種模式都是通過瀏覽器接口實現的,除此之外vue-router還為非瀏覽器環境准備了一個abstract模式,其原理為用一個數組stack模擬出瀏覽器歷史記錄棧的功能。這里主要講解hash模式和history模式實現前端路由的原理。

1.hash模式:監聽瀏覽器地址hash值變化,執行相應的js改變網頁內容

  • 本身以及它后面的字符稱作hash,可通過window.location.hash屬性讀取

  • url中可以帶有一個hash,比如 http://localhost:9000/#/song 中的hash值就是 #/song

  • hashchange事件觸發:

    • 直接更改瀏覽器地址,在最后面增加或者改變#hash

    • 通過改變locatin.href或者location.hash的值(window.location.href:表示重定向,后面跟着的是完整的url地址。window.location.hash:得到的是錨鏈接)

    • 通過觸發點擊帶錨點的鏈接

    • 瀏覽器前進后退可能導致hash的變化,前提是兩個網頁地址中的hash值不同

  • hash實現前端路由的原理:
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>Hash實現前端路由的原理</title>
        </head>
        <body>
            <!-- 跳轉組件是由a標簽實現  -->
            <a href="/1" class="spa">1</a>
            <a href="/2" class="spa">2</a>
            <a href="/3" class="spa">3</a>
            <script>
                document.querySelectorAll('.spa').forEach(item => {
                    item.addEventListener('click', e => {
                        // 阻止a標簽的默認事件
                        e.preventDefault();
                        //幫助改變url地址
                        let link = item.textContent  //獲取文本內容
                        location.hash = link;
                        
                    },false)
                })
                //監聽路由的變化
                window.addEventListener('hashchange', e => {
                    console.log({
                        location:location.href,
                        hash:location.hash
                    })
                })
            </script>
        </body>
    </html>

2.history模式:利用history API實現url地址改變,網頁內容改變

  • History 對象是 window 對象的一部分,可通過 window.history 屬性對其進行訪問。HTML5 History API提供了一種功能,能讓開發人員在不刷新整個頁面的情況下修改站點的URL,就是利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。

  • History對象方法:
    • history.back()  #加載 history 列表中的前一個 URL
    • history.forward()  #加載 history 列表中的下一個 URL
    • history.go(n)  #加載 history 列表中的某個具體頁面   
  • HTML5新接口:history.pushState(stateObj,title,url)

    • window.history.pushState(stateObj, title, targetURL); @狀態對象:傳給目標路由的信息,可為空 @頁面標題:目前所有瀏覽器都不支持,填空字符串即可 @可選url:目標url,不會檢查url是否存在,且不能跨域。如不傳該項,即給當前url添加sateObj
    • pushState方法不會觸發頁面刷新,只是導致history對象發生變化,改變網址,網頁不會真的跳轉,本質上網頁還停留在原頁面

    • 這里的url受到同源策略的限制

  • popstate事件觸發:每當同一個文檔的瀏覽歷史(即history對象)出現變化時,就會觸發popstate事件
    • popstate事件會在點擊后退、前進按鈕(或調用history.back()history.forward()history.go()方法)時觸發。history.pushState()或者history.replaceState()形成的歷史節點中前進后退會形成頁面切換。注意:僅僅調用pushState方法或replaceState方法,並不會觸發該事件,只有用戶點擊瀏覽器倒退按鈕 和前進按鈕,或者使用JavaScript調用back、forward、go方法時才會觸發。另外,該事件只針對同一個文檔,如果瀏覽歷史的切換,導致加載不同的文檔,該事件也不會觸發
    • 用法:使用的時候,可以為popstate事件指定回調函數。這個回調函數的參數是一個event事件對象,它的state屬性指向pushState和replaceState方法為當前URL所提供的狀態對象(即這兩個方法的第一個參數)
  • history實現前端路由的原理:
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>History實現前端路由的原理</title>
        </head>
        <body>
            <!-- 跳轉組件是由a標簽實現  -->
            <a href="/1" class="spa">1</a>
            <a href="/2" class="spa">2</a>
            <a href="/3" class="spa">3</a>
            <script>
                //監聽a標簽
                //querySelectorAll找出所有匹配的節點並返回數組.
                document.querySelectorAll(".spa").forEach(item => {
                    item.addEventListener("click",e=>{
                        // 阻止a標簽的默認事件
                        e.preventDefault();
                        //幫助改變url地址
                        let link = item.textContent  //獲取文本內容
                        
                        // 檢查是否支持history和pushState
                        if(window.history && window.history.pushState){
                            //支持History API
                            window.history.pushState({name:"history"},link,link)
                        }else{
                            //不支持,可以使用一些Ployfill插件庫來實現(Polyfill 是一塊代碼(通常是 Web 上的 JavaScript),用來為舊瀏覽器提供它沒有原生支持的較新的功能。)
                        }
                    },false)
                })  
                
                //監聽路由
                window.addEventListener('popstate',e=>{
                    console.log({
                        location:location.href,
                        state:e.state
                    })
                })
                
            </script>
        </body>
    </html>

3.history和hash兩種模式比較

  • pushState設置的新URL可以是與當前同源的任意URL;而hash只可修改#后面的部分,故只可設置與當前同文檔的URL

  • pushState設置的新URL可以與當前URL一模一樣,這樣也會把記錄添加到棧中;而hash設置的新值必須與原來不一樣才會觸發記錄添加到棧中

  • pushState通過stateObject可以添加任意類型的數據到記錄中;而hash只可添加短字符串

  • pushState可額外設置title屬性供后續使用

4.history模式的一個問題

  • 對於單頁應用來講,理想的使用場景是僅在進入應用時加載index.html,后續的網絡操作通過Ajax完成,不會根據URL重新請求頁面,但是難免遇到特殊情況,比如用戶直接在地址欄輸入並回車,瀏覽器重啟重新加載應用等。

  • 例子:

    • 在hash模式下,對於http://oursite.com/#/user/id 如果重新請求,只會發送http://oursite.com 故在hash模式下遇到根據URL請求頁面的情況不會有問題。hash模式僅改變hash部分的內容,而hash部分是不會包含在HTTP請求中的

    • 在history模式下,對於http://oursite.com/#/user/id 會將該URL修改得和正常請求后端的URL一樣,在此情況下重新向后端發送請求,如后端沒有配置對應/user/id的路由處理,則會返回404錯誤

  • 解決辦法:官方推薦的解決辦法是在服務器端增加一個覆蓋所有情況的候選資源:如果URL匹配不到任何靜態資源,則應該返回一個index.html頁面,這個頁面就是你app依賴的頁面。同時這么做以后,服務器就不會再返回404錯誤頁面,因為對於所有路徑都會返回index.html文件。為了避免這種情況,在Vue應用里面覆蓋所有的路由情況,然后在給出一個404頁面。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM