- 1.導航被觸發
- 2.在失活的組件里調用離開守衛:beforeRouteLeave —— 組件內守衛(離開組件)。
- 3.調用全局的beforeEach守衛 —— 全局守衛(進入組件)。
- 4.在重用組件里調用deforeRouteUpdatar守衛(2.2+)—— 組件內守衛(組件復用時調用/foo/:id)。
- 5.在路由配置里調用beforeEnter。—— 路由獨享守衛(進入組件)。
- 6.解析異步路由組件。
- 7.在被激活的組件里調用beforeRouteEnter。—— 組件內守衛(進入組件)。
- 8.調用全局的beforesolve守衛(2.5)。—— 全局解析守衛,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被調用。
- 9.導航被確認。
- 10.調用全局的afterEach鈎子。——全局后置鈎子(確定要進入的路由之后,vue實例創建之前,這個鈎子只接收to,from兩個參數,沒有next參數)。
- 11.觸發DOM更新。
一、導航守衛
官方手冊:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
vue-router的導航守衛在官方中有很詳細的說明,應用也是比較簡單,主要並不在於導航本身的應用,而是要理解導航守衛的所有API是在離開當前路由組件之后,進入新的路由組件之前被觸發,在這個過程中來實現是否決定進入下一個路由組件或者留在當前路由組件,還是重定向到別的組件中,主要用於處理路由切換業務。導航守衛的業務必定會存在路由之間的數據操作,這時候就需要配置路由元信息來實現。
1 const router = new VueRouter({ ... }) 2 router.beforeEach((to, from, next) => { 3 // ... 4 })
- to:Route:即將要進入的目標路由對象
- from:Route:當前導航要離開的路由
- next:function:最后調用該方法來resolve這個鈎子(最終決定渠道那個路由組件),執行next方法需要的參數:
next() //去到目標路由對象 next(false) //中斷導航,留在真要離開的from路由。如果瀏覽器的URL地址改變(用戶手動或者瀏覽器后退按鈕),那么url地址會重置到from路由對應的地址 next('/') next({path:'/'}) //跳轉到指定的地址,當前導航中斷,然后進入到一個新的導航 next(error) //2.4.0如果傳入next的參數是一個Error實例,則導航會被終止且該錯誤會被傳遞給router.onError()注冊過的回調。
要確保next()方法調用,不然鈎子就不會被resolved。
導航守衛API的參數幾乎沒有差別,基本上都使用“to,from,next”這三個參數,幾乎vue實例在這些路由API中也不能用this獲取,這時候獲取的this基本上都是undefined,但也有例外:
router.beforeResolve((to,from,next) => {})//全局解析守衛 this指向undefined router.afterEach((to,from) => {}) //全局后置守衛沒有next參數,並且this指向也是undefined beforeEnter:(to,from,next) => {} //路由獨享守衛,this指向undefined //組件內的守衛 beforeRouteEnter(to,from,next){} // 在渲染該組件的對應路由被 confirm 前調用; 不!能!獲取組件實例 `this`; 因為當守衛執行前,組件實例還沒被創建 beforeRouteUpdate(to,from,next){}// 在當前路由改變,但是該組件被復用時調用; 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候;由於會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鈎子就會在這個情況下被調用; 可以訪問組件實例 `this` beforeRouteLeave(to,from,next){}//導航離開該組件的對應路由時調用;可以訪問組件實例 `this`
beforeRouteEnter不能獲取this,但是能通過next傳入一個vue實例來獲取實例的一些數據。
1 beforeRouteEnter (to, from, next) { 2 next(vm => { 3 // 通過 `vm` 訪問組件實例 4 }) 5 }
但是注意beforeRouteUpdate和beforeRouteLeave中的next不能傳入vue實例,因為這兩個守衛已經可以通過this獲取當前組件實例對象了。
1 beforeRouteUpdate (to, from, next) { 2 // just use `this` 3 this.name = to.params.name 4 next() 5 } 6 // 7 beforeRouteLeave (to, from , next) { 8 const answer = window.confirm('Do you really want to leave? you have unsaved changes!') 9 if (answer) { 10 next() 11 } else { 12 next(false) 13 } 14 }
二、路由元信息
從上一節的路由守衛的業務邏輯來看,必然會引出一個思考,就是怎么緩存路由訪問權限,要不然每一次都需要進行權限驗證,如果驗證需要訪問服務器的話,這樣豈不是要消耗大量不必要的服務器資源,所以路由元信息就可以幫助我們來解決這個問題:
在定義路由的時候可以在路由中配置mata字段:
1 const router = new VueRouter({ 2 routes: [ 3 { 4 path: '/foo', 5 component: Foo, 6 children: [ 7 { 8 path: 'bar', 9 component: Bar, 10 // a meta field 11 meta: { requiresAuth: true } 12 } 13 ] 14 } 15 ] 16 })
meta字段可以通過$route對象來獲取,但是$route上沒有這個屬性,因為$route.metched[n].meta來獲取,$route.metched[n]緩存的是URL節點的路由配置數據,從第一個節點開始到當前節點按照順序匹配到metched數組元素中。
1 router.beforeEach((to, from, next) => { 2 if (to.matched.some(record => record.meta.requiresAuth)) { 3 // this route requires auth, check if logged in 4 // if not, redirect to login page. 5 if (!auth.loggedIn()) { 6 next({ 7 path: '/login', 8 query: { redirect: to.fullPath } 9 }) 10 } else { 11 next() 12 } 13 } else { 14 next() // 確保一定要調用 next() 15 } 16 })
簡單的獲取:
this.loginFlag = this.$route.matched[0].meta.login;
三、路由懶加載
官方手冊:https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
將Router引入組件模塊使用路由懶加載的方式加載:
const Home = () => import('./views/Home.vue')
路由懶加載還組合了預加載模式,當進入應用時首先加載首屏需要的組件模塊進行渲染,剩下的組件模塊會在網絡空閑的時候預加載到緩存中,當需要到某個模塊時直接調取緩存中的資源。