Vue ——Vue-router有幾種模式?


Vue-router有幾種模式?如何實現?

  Vue-router 是vue框架的路由插件。

  Vue-router 有兩種模式:Hash 模式和 History 模式。在開發的時候可以通過使用在路由配置中配置mode這個屬性的值來配置使用哪種路由,如果不配置這個字段就默認是 hash 模式。

  * Hash 模式:該模式有一個很明顯的標志就是 URL 中帶有 #,我們可以通過 window.location.hash 來獲取這個值。

  * History 模式:該模式是由 h5 提供的 history 對象實現的。

  我們可以通過源碼來看看路由是怎么實現的:

路由模式參數:

  在 Vue-router 中是通過mode 這一個參數來實現控制路由的實現模式的:

const router = new VueRouter({
  mode: 'history',
  // 配置路由
  routes:[...]
})

  在創建路由的實例中,我們通過 mode 參數指定當前創建路由的方式,我們可以通過VueRouter 類的定義來入手:

export default class VueRouter {
  
  mode: string; // 傳入的字符串參數,指示history類別
  history: HashHistory | HTML5History | AbstractHistory; // 實際起作用的對象屬性,必須是以上三個類的枚舉
  fallback: boolean; // 如瀏覽器不支持,'history'模式需回滾為'hash'模式
  
  constructor (options: RouterOptions = {}) {
    
    let mode = options.mode || 'hash' // 默認為'hash'模式
    this.fallback = mode === 'history' && !supportsPushState // 通過supportsPushState判斷瀏覽器是否支持'history'模式
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract' // 不在瀏覽器環境下運行需強制為'abstract'模式
    }
    this.mode = mode

    // 根據mode確定history實際的類並實例化
    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if (process.env.NODE_ENV !== 'production') {
          assert(false, `invalid mode: ${mode}`)
        }
    }
  }

  init (app: any /* Vue component instance */) {
    
    const history = this.history

    // 根據history的類別執行相應的初始化操作和監聽
    if (history instanceof HTML5History) {
      history.transitionTo(history.getCurrentLocation())
    } else if (history instanceof HashHistory) {
      const setupHashListener = () => {
        history.setupListeners()
      }
      history.transitionTo(
        history.getCurrentLocation(),
        setupHashListener,
        setupHashListener
      )
    }

    history.listen(route => {
      this.apps.forEach((app) => {
        app._route = route
      })
    })
  }

  // VueRouter類暴露的以下方法實際是調用具體history對象的方法
  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    this.history.push(location, onComplete, onAbort)
  }

  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    this.history.replace(location, onComplete, onAbort)
  }
}

  從上面可以看出:

  * 作為參數傳遞進入的字符串屬性 mode 只是一個標記,用來指示實際作用的對象屬性 history 的實現類,兩者對應的關系如下:

mode history的實現類
history HTML5History
hash HashHistory
abstract AbstractHistory

  * 在初始化對應的 history 之前 ,會對 mode 做一些判斷:如果瀏覽器不支持 HTML5History 方式(通過 supportsPushState 來檢測),則 mode 模式就強制設置為 Hash 模式,如果當前不是在瀏覽器中執行,就 mode 模式就強制設置為 abstract 模式。

  * VueRouter 類中共的 onReady(),push(), 方法只是一個代理,它真正的實現是具體 History 對象的應用方法,在 init() 方法中初始化的時候,就根據 history 對象

具體的實現類來執行不同的操作。

  在瀏覽器環境下的兩種模式,分別是在 HTML5History , HashHistory 兩個類中實現的。

 

History模式實現的路由

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

   在Html5開始, History interface 提供了兩個新的方法:pushState(),replaceState() 是的我們可以對瀏覽器的歷史記錄棧進行修改

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

 window.history.replaceState(stateObject,title,Url) 

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

  * title: 所添記錄的標題

  * URL: 所添記錄的URL

  這兩個方法都有一個共同的特點就是,當他們修改了瀏覽器的歷史記錄棧后,雖然當前的URL 改變了,但是不會立即發送請求該 URL 的資源,這就為單頁面應用前端路由“更新視圖當不重新請求頁面”提供了基礎。

 

Hash模式實現的路由

  這種模式實現的路由,在通過鏈接后面添加 “#”+路由名字。

  hash 雖然是出現在 url 中,但是它不會被包含在 HTTP 請求里面。它是用來指示瀏覽器的動作的,對服務端完全是沒有作用的,因此,改變 hash 是不會重新加載頁面的。

  可以給 hash 的改變添加監聽事件:

  window.addEventLIstener("hashchange",funcRef,false);

  每一次改變 hash ,就會在瀏覽器的訪問歷史記錄中添加一個記錄。

  利用 Hash 的以上特點可以實現前端路由的“更新視圖但是不重新加載請求頁面”的功能了。

兩種模式的比較

  在一般的需求場景中,hash 模式和 history 模式是差不多的,但是它們之間的區別主要如下:

  * pushState 設置的新 URL 可以是與當前 URL 同源的任意 URL; 而修改 hash 只能修改 # 符號之后的部分;

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

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

  * pushState 可以額外設置 title 屬性后供后續使用;

 

History 模式的一個問題:

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

  hash 模式只會改變 hash 部分的內容,並且 hash 部分的內容是不會包含在 Http 請求里面的,

http://oursite.com/#/user/id  //只會發送 http://oursite.com/

  在 Hash 模式下根據 url 請求頁面時不會出現什么問題的,但是如果使用的是 History 模式的,則會將 URL 修改得就和正常請求后端的 URL 一樣。

   http://oursite.com/user/id

  在次情況下向后端發送請求的話,如果后端沒有配置對應的/user/id 的路由處理,就會返會404錯誤。

  如果一定要使用 History 模式的話,為了防止頁面刷新出現404情況,可以使用官方提供的解決方法是在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何的靜態資源,則返回一個同一個 html.index 頁面,這個頁面就是你應用依賴的頁面,但是這么做之后,服務器就不會返回404錯誤,因為這個時候,所有的頁面都會返回 index 頁面,為了避免這種情況,在 Vue 應用里面覆蓋了所有的路由之后,然后再給出一個404頁面。

 


免責聲明!

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



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