vue router 路由鉤子使用

Vue-Router導航守衛:

有的時候,我們需要通過路由來進行一些操作,比如最常見的登錄權限驗證,當用戶滿足條件時,才讓其進入導航,否則就取消跳轉,並跳到登錄頁面讓其登錄。

爲此我們有很多種方法可以植入路由的導航過程:全局的, 單個路由獨享的, 或者組件級的,推薦優先閱讀路由文檔

全局守衛

vue-router全局有三個守衛:

  1. router.beforeEach 全局前置守衛 進入路由之前
  2. router.beforeResolve 全局解析守衛(2.5.0+) 在beforeRouteEnter調用之後調用
  3. router.afterEach 全局後置鉤子 進入路由之後

使用方法

    // main.js 入口文件
    import router from './router'; // 引入路由
    router.beforeEach((to, from, next) => { 
      next();
    });
    router.beforeResolve((to, from, next) => {
      next();
    });
    router.afterEach((to, from) => {
      console.log('afterEach 全局後置鉤子');
    });
複製代碼

to,from,next 這三個參數:

to和from是將要進入和將要離開的路由對象,路由對象指的是平時通過this.$route獲取到的路由對象。

next:Function 這個參數是個函數,且必須調用,否則不能進入路由(頁面空白)。

  • next() 進入該路由。

  • next(false): 取消進入路由,url地址重置爲from路由地址(也就是將要離開的路由地址)。

  • next 跳轉新路由,當前的導航被中斷,重新開始一個新的導航。

      我們可以這樣跳轉:next('path地址')或者next({path:''})或者next({name:''})
      且允許設置諸如 replace: true、name: 'home' 之類的選項
      以及你用在router-link或router.push的對象選項。
    複製代碼

路由獨享守衛

如果你不想全局配置守衛的話,你可以爲某些路由單獨配置守衛:

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => { 
            // 參數用法什麼的都一樣,調用順序在全局前置守衛後面,所以不會被全局守衛覆蓋
            // ...
          }
        }
      ]
    })
複製代碼

路由組件內的守衛:

  1. beforeRouteEnter 進入路由前
  2. beforeRouteUpdate (2.2) 路由複用同一個組件時
  3. beforeRouteLeave 離開當前路由時

文檔中的介紹:

  beforeRouteEnter (to, from, next) {
    // 在路由獨享守衛後調用 不!能!獲取組件實例 `this`,組件實例還沒被創建
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,但是該組件被複用時調用 可以訪問組件實例 `this`
    // 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 由於會渲染同樣的 Foo 組件,因此組件實例會被複用。而這個鉤子就會在這個情況下被調用。
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該組件的對應路由時調用,可以訪問組件實例 `this`
  }
複製代碼

beforeRouteEnter訪問this

因爲鉤子在組件實例還沒被創建的時候調用,所以不能獲取組件實例 this,可以通過傳一個回調給next來訪問組件實例 。

但是回調的執行時機在mounted後面,所以在我看來這裏對this的訪問意義不太大,可以放在created或者mounted裏面。

    beforeRouteEnter (to, from, next) {
    console.log('在路由獨享守衛後調用');
      next(vm => {
        // 通過 `vm` 訪問組件實例`this` 執行回調的時機在mounted後面,
      })
    }
複製代碼

beforeRouteLeave:

導航離開該組件的對應路由時調用,我們用它來禁止用戶離開,比如還未保存草稿,或者在用戶離開前,將setInterval銷燬,防止離開之後,定時器還在調用。

    beforeRouteLeave (to, from , next) {
      if (文章保存) {
        next(); // 允許離開或者可以跳到別的路由 上面講過了
      } else {
        next(false); // 取消離開
      }
    }
複製代碼

關於鉤子的一些知識:

路由鉤子函數的錯誤捕獲

如果我們在全局守衛/路由獨享守衛/組件路由守衛的鉤子函數中有錯誤,可以這樣捕獲:

    router.onError(callback => { 
    // 2.4.0新增 並不常用,瞭解一下就可以了 
      console.log(callback, 'callback');
    });
複製代碼

在路由文檔中還有更多的實例方法:動態添加路由等,有興趣可以瞭解一下。

跳轉死循環,頁面永遠空白

我瞭解到的,很多人會碰到這個問題,來看一下這段僞代碼:

    router.beforeEach((to, from, next) => {
      if(登錄){
         next()
      }else{
          next({ name: 'login' }); 
      }
    });
複製代碼

看邏輯貌似是對的,但是當我們跳轉到login之後,因爲此時還是未登錄狀態,所以會一直跳轉到login然後死循環,頁面一直是空白的,所以:我們需要把判斷條件稍微改一下。

    if(登錄 || to.name === 'login'){ next() } // 登錄,或者將要前往login頁面的時候,就允許進入路由
複製代碼

全局後置鉤子的跳轉:

文檔中提到因爲router.afterEach不接受next函數所以也不會改變導航本身,意思就是隻能當成一個鉤子來使用,但是我自己在試的時候發現,我們可以通過這種形式來實現跳轉:

    // main.js 入口文件
    import router from './router'; // 引入路由
    router.afterEach((to, from) => {
      if (未登錄 && to.name !== 'login') {
        router.push({ name: 'login' }); // 跳轉login
      }
    });
複製代碼

額,通過router.beforeEach 也完全可以實現且更好,我就騷一下。

完整的路由導航解析流程(不包括其他生命週期):

  1. 觸發進入其他路由。
  2. 調用要離開路由的組件守衛beforeRouteLeave
  3. 調用局前置守衛:beforeEach
  4. 在重用的組件裏調用 beforeRouteUpdate
  5. 調用路由獨享守衛 beforeEnter
  6. 解析異步路由組件。
  7. 在將要進入的路由組件中調用beforeRouteEnter
  8. 調用全局解析守衛 beforeResolve
  9. 導航被確認。
  10. 調用全局後置鉤子的 afterEach 鉤子。
  11. 觸發DOM更新(mounted)。
  12. 執行beforeRouteEnter 守衛中傳給 next 的回調函數


鏈接:https://juejin.im/post/5b41bdef6fb9a04fe63765f1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章