Vue Router 路由實現原理實現原理


Vue Router 路由實現原理

 

一、概念

  通過改變 URL,在不重新請求頁面的情況下,更新頁面視圖。

 

二、實現方式

  更新視圖但不重新請求頁面,是前端路由原理的核心之一,目前在瀏覽器環境中這一功能的實現主要有2種方式:

    1.Hash --- 利用 URL 中的hash("#");

    2.利用 History interface 在HTML5中新增的方法。

 

  Vue 中,它是通過 mode 這一參數控制路由的實現模式:

 

const router=new VueRouter({
    mode:'history',
    routes:[...]
})

 

  創建 VueRouter 的實例對象時,mode 以構造參數的形式傳入,如下代碼:

  

  源碼

 

  

  mode 參數:

    1.默認 hash

    2. history。如果瀏覽器不支持 history 新特性,則采用 hash

    3. 如果不在瀏覽器環境下,就采用 abstract(Node環境下)

    

 

  mode 區別:

    1. mode:"hash"  多了 “#”

http://localhost:8080/#/login

    

    2.mode:"history" 

http://localhost:8080/recommend

  

  HashHistory:

    hash("#") 的作用是加載 URL 中指示網頁中的位置。

    # 本身以及它后面的字符稱職位 hash,可通過 window.location.hash 獲取

    特點:

      1. hash 雖然出現在 url 中,但不會被包括在 http 請求中,它是用來指導瀏覽器動作的,對服務器端完全無用,因此,改變 hash 不會重新加載頁面。

      2. 可以為 hash 的改變添加監聽事件:

      window.addEventListener("hashchange",funcRef,false)

      3. 每一次改變 hash(window.localtion.hash),都會在瀏覽器訪問歷史中增加一個記錄。

    利用 hash 的以上特點,就可以來實現前端路由"更新視圖但不重新請求頁面"的功能了。

 

    HashHistory 擁有兩個方法,一個是 push, 一個是 replace

1
兩個方法:HashHistory.push() 和 HashHistory.replace()

  

    HashHistory.push()  將新路由添加到瀏覽器訪問歷史的棧頂

  

  HashHisttory.push()

 

    

    從設置路由改變到視圖更新的流程:  

1
$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()

  

    解析:

復制代碼
1 $router.push() //調用方法

2 HashHistory.push() //根據hash模式調用,設置hash並添加到瀏覽器歷史記錄(添加到棧頂)(window.location.hash= XXX)

3 History.transitionTo() //監測更新,更新則調用History.updateRoute()

4 History.updateRoute() //更新路由

5 {app._route= route} //替換當前app路由

6 vm.render() //更新視圖
復制代碼

 

    transitionTo() 方法是父類中定義的是用來處理路由變化中的基礎邏輯的,push() 方法最主要的是對 window 的 hash 進行了直接賦值:

  

window.location.hash=route.fullPath

 

    hash 的改變會自動添加到瀏覽器的訪問歷史記錄中。
    那么視圖的更新是怎么實現的呢,我們來看看父類 History 中的 transitionTo() 方法:

    

復制代碼
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
  const route = this.router.match(location, this.current)
  this.confirmTransition(route, () => {
    this.updateRoute(route)
    ...
  })
}

updateRoute (route: Route) {
  
  this.cb && this.cb(route)
  
}

listen (cb: Function) {
  this.cb = cb
}
復制代碼

 

    可以看到,當路由變化時,調用了Hitory中的this.cb方法,而this.cb方法是通過History.listen(cb)進行設置的,回到VueRouter類定義中,找到了在init()中對其進行了設置:

    

復制代碼
init (app: any /* Vue component instance */) {
    
  this.apps.push(app)

  history.listen(route => {
    this.apps.forEach((app) => {
      app._route = route
    })
  })
}
復制代碼

 

 

    HashHistory.replace()

      replace()方法與push()方法不同之處在於,它並不是將新路由添加到瀏覽器訪問歷史的棧頂,而是替換掉當前的路由

 

  HashHisttory.replace()

      

 

 

  HTML5History

    History interface 是瀏覽器歷史記錄棧提供的接口,通過back()、forward()、go()等方法,我們可以讀取瀏覽器歷史記錄棧的信息,進行各種跳轉操作。

    從 HTML5開始,History interface 提供了2個新的方法:pushState()、replaceState() 使得我們可以對瀏覽器歷史記錄棧進行修改:

  window.history.pushState(stateObject,title,url)
  window.history,replaceState(stateObject,title,url)

    

    stateObject:當瀏覽器跳轉到新的狀態時,將觸發 Popstate 事件,該事件將攜帶這個 stateObject 參數的副本

    title:所添加記錄的標題

    url:所添加記錄的 url

    

    這2個方法有個共同的特點:當調用他們修改瀏覽器歷史棧后,雖然當前url改變了,但瀏覽器不會立即發送請求該url,這就為單頁應用前端路由,更新視圖但不重新請求頁面提供了基礎

    

    1.push

      與hash模式類似,只是將window.hash改為history.pushState

    2.replace

      與hash模式類似,只是將window.replace改為history.replaceState

    3.監聽地址變化

      在HTML5History的構造函數中監聽popState(window.onpopstate)


    
  View Code

 

 

  兩種模式比較

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

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

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

  4. history模式則會將URL修改得就和正常請求后端的URL一樣,如后端沒有配置對應/user/id的路由處理,則會返回404錯誤


免責聲明!

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



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