一、分類:全局守衛、路由獨享守衛、組件內路由守衛
全局守衛:
router.beforeEach((to, form, next) => { console.log('全局前置守衛 beforeEach') next() }) router.beforeResolve((to, form, next) => { console.log('全局解析守衛 beforeResolve') next() }) router.afterEach((to, form) => { console.log('全局后置守衛 afterEach') })
使用場景:
全局前置守衛:用於登錄時驗證token是否有效、開啟進度條 NProgress
全局解析守衛:
全局后置守衛:關閉進度條
路由獨享守衛:
{ path: '/list', name: 'list', alias: '/aaa', component: () => import('@views/List'), children: [ { path: ':id', name: 'details', component: () => import('@views/Details'), props: true, beforeEnter: (to, from, next) => { console.log('路由獨享守衛 beforeEnter') next() } } ] }
使用場景:進入當前路由前要干什么事就在這里處理
組件內守衛:
beforeRouteEnter(to, from, next) { console.log('組件內路由前置守衛 beforeRouteEnter', this) // 訪問不到this next((vm) => { console.log('組件內路由前置守衛 vm', vm) // vm 就是this }) }, beforeRouteUpdate(to, from, next) { console.log('組件內路由更新守衛 beforeRouteUpdate') next() }, beforeRouteLeave(to, from, next) { console.log('組件內路由離開守衛 beforeRouteLeave', this) next() }
使用場景:
組件內前置守衛:在進入當前路由前,對頁面某一部分組件進行刷新,可以通過改變key值的方式進行刷新,具體見 vue詳情頁回到列表頁定位到之前位置(keep-alive)
*組件內路由更新守衛:
在vue官網中有過介紹:
他的意思是說,當使用動態路由傳值時,/user/1 和 /user/2 使用的是同一個組件,那么既然使用了同一個組件,vue或默認復用這個組件,也就是他相當於使用了keep-alive緩存,不會經歷創建和銷毀的那一套流程,所以路由參數發生變化了,組件沒有反應。對應的解決辦法有兩種:
組件內路由離開守衛:在退出時詢問需不需要保持至草稿箱,或者詢問當前未支付,是否留下支付完再走
二、路由的執行順序:
全局前置守衛 beforeEach
路由獨享守衛 beforeEnter
組件內路由前置守衛 beforeRouteEnter
全局解析守衛 beforeResolve
組件生命周期:掛載后 mounted
三、路由守衛的參數:
to:路由要去哪兒
from:路由來自哪兒
next:是一個函數,路由守衛中一定要調用這個函數來使當前路由狀態為 reslove。執行的效果由next函數中的參數決定,它的參數有以下4種情況:
next():沒有參數,表示可以進入到to的路由中
next(false):參數為一個布爾值false,中斷當前的導航,回到from路由
next('/') 或 next({ path: '/' }):參數為一個路徑,相當於執行了this.$router.push('/')
next(error):參數為error,中斷當前導航,將該錯誤傳遞給router.onError()注冊過的回調
注意:必須要確保next函數在任何給定的導航守衛中都被調用過一次。它可以出現多次,但是只能在所有的邏輯路徑都不重疊的情況下,否則會報錯。
錯誤的案例:
router.beforeEach((to, from, next) => { if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' }) // 如果用戶未能驗證身份,則 `next` 會被調用兩次 next() })
正確的寫法:
router.beforeEach((to, from, next) => { if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' }) else next() })