vue-router的導航鈎子(導航守衛)


在做vue項目的時候,要求用戶在頁面訪問前先登錄,或在離開頁面前發出提醒。vue官方提供的路由管理器 vue-router 提供的導航鈎子,通過跳轉或取消的方式守衛導航。以下總結了路由鈎子函數的使用方法和一些使用場景。

 

一、全局守衛

  • router.beforeEach 路由改變前的鈎子

    const router = new VueRouter({ ... })
    
    router.beforeEach((to, from, next) => {
        ... ...
    })

    其中:

    • to:將要訪問的路徑

    • from:代表從哪個路徑跳轉來的

    • next:是一個函數,表示放行。有如下幾種調用方式

      • next():如果一起正常,則調用該方法進入下一個鈎子;

      • next(false):中斷當前導航,即路由地址不發生變化;

      • next('/xxx') 或 next({path: '/xxx'}):強制跳轉到指定路徑;

      • next(error):如果傳入的是一個Error實例,則導航會被中斷且該錯誤會被傳遞給 router.onError() 注冊過的回調。

    使用:

    • 使用該函數,一定要調用 next(),否則鈎子函數不能 resolve;

    • 該方法比較常用於:驗證用戶訪問權限。

      比如:一個系統需要先驗證用戶是否登錄,如果登錄了就可以訪問,否則直接跳轉到登錄頁面。具體實現如下:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import { getToken } from '@Utils/session.utils' // 登錄用戶的token
    import Login from '../pages/Login.vue' //引入登錄頁
    const Home = () => import('../pages/Home.vue')  //引入首頁
    
    Vue.use(VueRouter) // 全局注入router
    
    // 配置路由參數
    const routes = [
      { path: '/login', name: 'login', component: Login },
      { path: '/home', name: 'home', component: Home }
    ]
    
    const router = new VueRouter({
      routes
    })
    
    // 全局掛載路由導航守衛:驗證用戶是否登錄
    router.beforeEach((to, from, next) => {
      if (to.name !== 'login' && !getToken()) next('/login') // 如果用戶不是訪問登錄頁且沒有登錄,則強制跳轉到登錄頁
      else next()
    })
    
    export default router
  • router.beforeResolve 在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,該鈎子函數就被調用。

  該方法我在項目中暫時還未使用到,具體使用場景歡迎大家補充 :)

  • router.afterEach 路由改變后的鈎子

    router.afterEach((to, from) => {
        ... ...
    })

    該方法同全局前置守衛 router.beforeEach 不同的是少了 next() 函數,也不會改變導航本身。

    使用場景:

    • 切換路由,將頁面的滾動位置返回到頂部。

      例如:一個頁面比較長,當滾動到某個位置后切換路由,這時跳轉的頁面滾動條位置默認是前一個頁面離開時停留的位置,可以通過該鈎子函數將滾動條位置重置。

    // 切換路由,頁面返回到頂部
    router.afterEach((to, from) => {
        window.scrollTo(0, 0)
    })

 

二、路由獨享的守衛

  • beforeEnter 對某個路由的單獨守衛

    const routes = [
        { path: '/login', name: 'login', component: Login },
        { 
            path: '/home', 
            name: 'home', 
            component: Home,
            beforeEnter: (to, from, next) => {
                ... ...
            }
          }
    ]
    
    const router = new VueRouter({
      routes
    })

    使用:

    • 該方法的參數使用同全局前置守衛 router.beforeEach 是一樣的;

    • 在路由配置上直接定義;
    • 例如:根據登錄用戶的不同角色,展示不同的模塊;或者給指定路由組件單獨添加動畫。

import Vue from 'vue'
import VueRouter from 'vue-router'
import { getUserRole } from '@Utils/session.utils' // 登錄用戶的角色

const UserCenter = () => import('../pages/UserCenter.vue')

const routes = [
    ... ...
    { 
        path: '/usercenter', 
        name: 'usercenter', 
        component: UserCenter,
        beforeEnter: (to, from, next) => {
            if(getUserRole() === 'admin') next('/admincenter')
            else next()
        }
    }
]

 

三、組件內的守衛

  • beforeRouteEnter(to, from, next) 在進入當前組件對應的路由前調用

    export default {
        data() { ... },
        beforeRouteEnter(to, from, next) {
            ... ...
        }
    }

    注意:

    • 該函數內不能訪問當前組件實例 this,因為函數在對應路由被 comfirm 前調用,此時將要渲染的組件實例還沒被創建;

    • 可以通過給 next 傳遞一個回調來訪問組件實例,即把組件實例 vm 作為回調方法的參數;該回調的執行在 mounted 后面;

      beforeRouteEnter (to, from, next) {
          next(vm => {
              // 通過 vm 來訪問組件實例
          })
      }
    • beforeRouteEnter 是支持給 next 傳遞回調的唯一守衛。

    使用場景:

    • 例如:從一個列表頁進入到詳情頁,然后再返回到列表頁,要求保留離開列表頁之前訪問的數據及滾動位置,從其他頁面重新進入列表頁,獲取最新的數據。具體實現請點這里

  • beforeRouteUpdate(to, from, next) 在當前路由改變,但是該組件被復用時調用

    beforeRouteUpdate (to, from, next) {
        ... ...
    }

    注:

    • 該函數內可以訪問當前組件實例 this

    • 例如:在一個帶有動態參數的路徑 /detail/:id,在 /detail/aaa/detail/bbb 之間跳轉的時候,因為兩個路由渲染的是同個 Detail 組件,因此原來的組件實例會被復用(比起銷毀再創建,復用則會更加高效),在這種情況下這個鈎子會被調用,而組件的生命周期鈎子不會再被調用。

  • beforeRouteLeave(to, from, next) 在離開當前組件對應的路由前調用

    beforeRouteLeave (to, from, next) {
        ... ...
    }

    注:

    • 該函數內可以訪問當前組件實例 this

    • 比如:用戶在當前頁面有還未保存的內容時突然離開,阻止頁面跳轉並給出提示,或者在用戶離開時清除或存儲一些信息等。

 

四、完整的導航解析流程

  1. 導航被觸發;

  2. 在失活的組件里調用 beforeRouteLeave 守衛;

  3. 調用全局的 beforeEach 守衛;

  4. 在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+);

  5. 在路由配置里調用 beforeEnter

  6. 解析異步路由組件;

  7. 在被激活的組件里調用 beforeRouteEnter

  8. 調用全局的 beforeResolve 守衛 (2.5+);

  9. 導航被確認;

  10. 調用全局的 afterEach 鈎子;

  11. 觸發 DOM 更新;

  12. 調用 beforeRouteEnter 守衛中傳給 next 的回調函數,創建好的組件實例會作為回調函數的參數傳入。

其實常用的也就那么幾個,理解了其用法,路由導航的解析流程也就明了了。

 

五、附:使用 watch 監測路由變化

除了使用鈎子函數外,我們也可以使用 watch 來監聽 $route 對象,然后根據路由參數的變化來進行響應。

<template>
    <div id=``"app"``>
        <keep-alive>
            <router-view/>
        </keep-alive>
    </div>
</template>

<script>
    export default {
        name: 'App',
        watch: {
            '$route' (to, from) {
                // 對路由變化作出響應...
            }
        }
    }
</script>

 


免責聲明!

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



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