在 vue 路由中,咱們會用導航守衛控制頁面的可否被進入查看,其中最後一步是調用 next() 函數,讓中斷的導航繼續進行vue
當一個導航觸發時,全局前置守衛按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛 resolve 完以前一直處於 等待中。因此確保要調用 next 方法,不然鉤子就不會被 resolved
關鍵點:vuex
next () 能夠傳入參數,實現跳轉到其餘頁面或者取消導航的功能。這時候要注意,不能堵住通道,要確保每個條件最後都能調用沒有傳遞參數的 next() 方法
。
不然,頁面會陷入無限刷新的死循環。由於傳入參數的 next() 方法會致使路由再次執行前置導航守衛,從而陷入循環。瀏覽器
例子1:驗證 token ,失敗則返回登陸頁cookie
router.beforeEach((to,from,next) =>{ if (sessionStorage.getItem("token")) { if(to.path === "/login"){ next({path:"/dashboard"}) } else{ alert("1") next() } }else{ next({path: "/login"}) // 會再次執行前置導航守衛,由於路徑變化 } })
上面的代碼表面看沒有問題:session
若是 sessionStorage 有 token,而且即將要進入的目標路徑是登錄頁,就跳轉到 /dashboard 頁,若是是其它的頁面,就直接進入異步
若是 sessionStorage 沒有 token 就跳轉到登錄頁async
可是代碼執行會引發死循環,緣由是沒有出口,執行 next({path: "/login"}) 會再次執行全局前置導航守衛。進入 /login 頁面前,就再次觸發守衛,一直重複進入ide
代碼改爲下面的就正常了:函數
router.beforeEach((to, from, next) => { let token = window.sessionStorage.getItem('token'); if (to.path != '/login' && !token) { next({ path: '/login' }) } else { if (to.path == '/login' && token) { next('/dashboard') } else { next() } } })
例子2:動態添加路由spa
router.beforeEach((to, from, next) => { function getRouteAndMenu () { // 本地沒有保存可訪問路由,就須要計算 store.dispatch('d2admin/user/GenerateRoutes') // 獲取可訪問路由,在 vuex 中保存 router.addRoutes(store.state.d2admin.user.accessedRouters) // 和原有的固定路由合併到一塊兒 const routeArray = routes.concat(store.state.d2admin.user.accessedRouters) // 處理路由 獲得每一級的路由設置 store.commit('d2admin/page/init', routeArray) // 設置頂欄菜單 store.dispatch('d2admin/menu/GenerateHeaderMenu', { role: store.state.d2admin.user.info.role, menuHeader }) // 設置側邊欄菜單 store.dispatch('d2admin/menu/GenerateMenu', { role: store.state.d2admin.user.info.role, menuAside }) // 獲取側邊欄菜單,在 vuex 中保存 store.dispatch('d2admin/menu/setMenuAside', { menuAside }) next({ ...to, replace: true }) // hack 以確保路由增長後,再進行跳轉 } if (from.name === null && to.name === '404') { // 避免刷新出現 404 頁面 getRouteAndMenu() } // 驗證當前路由全部的匹配中是否須要有登陸驗證的 if (to.matched.some(r => r.meta.auth)) { // 這裏暫時將cookie裏是否存有token做爲驗證是否登陸的條件 // 請根據自身業務須要修改 const token = util.cookies.get('token') if (token && token !== 'undefined') { const accessedRouters = store.state.d2admin.user.accessedRouters if (accessedRouters.length <= 0) { getRouteAndMenu() } else { next() } } else { // 沒有登陸的時候跳轉到登陸界面 // 攜帶上登錄成功以後須要跳轉的頁面完整路徑 next({ name: 'login', query: { redirect: to.fullPath } }) } } else { // 不須要身份校驗 直接經過 next() } })
上面的代碼,主要是實現計算動態路由並添加到原有路由裏、計算可展現的菜單欄,而後再跳轉到相應頁面的功能。
其中,next({ ...to, replace: true })
方法是一個 hack 方法,能確保路由添加了再進行跳轉
問題在於,這裏只將動態計算的路由保存到了內存,因此在頁面刷新時,須要從新計算並添加,因此添加了下面的代碼:
if (from.name === null && to.name === '404') { // 避免刷新出現 404 頁面 getRouteAndMenu() }
而這會致使頁面一直在重複執行 getRouteAndMenu() 操做,瀏覽器會重複導航進入當前刷新的頁面,
緣由:getRouteAndMenu 除了 hack 方法沒有提供 next() 通道,每次 hack 都會再次執行導航守衛
解決方法:
不用 hack ,改爲使用 async await ,按順序執行,最後 next()
router.beforeEach((to, from, next) => { async function getRouteAndMenu () { // 本地沒有保存可訪問路由,就須要計算 await store.dispatch('d2admin/user/GenerateRoutes') // 獲取可訪問路由,在 vuex 中保存 router.addRoutes(store.state.d2admin.user.accessedRouters) // 和原有的固定路由合併到一塊兒 const routeArray = routes.concat(store.state.d2admin.user.accessedRouters) // 處理路由 獲得每一級的路由設置 store.commit('d2admin/page/init', routeArray) // 設置頂欄菜單 await store.dispatch('d2admin/menu/GenerateHeaderMenu', { role: store.state.d2admin.user.info.role, menuHeader }) // 設置側邊欄菜單 await store.dispatch('d2admin/menu/GenerateMenu', { role: store.state.d2admin.user.info.role, menuAside }) // 獲取側邊欄菜單,在 vuex 中保存 await store.dispatch('d2admin/menu/setMenuAside', { menuAside }) next() } if (from.name === null && to.name === '404') { // 避免刷新出現 404 頁面 getRouteAndMenu() } // 驗證當前路由全部的匹配中是否須要有登陸驗證的 if (to.matched.some(r => r.meta.auth)) { // 這裏暫時將cookie裏是否存有token做爲驗證是否登陸的條件 // 請根據自身業務須要修改 const token = util.cookies.get('token') if (token && token !== 'undefined') { const accessedRouters = store.state.d2admin.user.accessedRouters if (accessedRouters.length <= 0) { getRouteAndMenu() } else { next() } } else { // 沒有登陸的時候跳轉到登陸界面 // 攜帶上登錄成功以後須要跳轉的頁面完整路徑 next({ name: 'login', query: { redirect: to.fullPath } }) } } else { // 不須要身份校驗 直接經過 next() } })