最近因為next()
遇到了不少問題,在這里記錄一下
首先是路由守衛,是不是感覺簡簡單單
beforeEach((to, from, next) => { to // 要去的路由 from // 當前路由 next() // 放行的意思 }
但是在看別的項目時常常能看到next('/logon') 、 next(to) 或者 next({ ...to, replace: true })
這又是啥意思呢
其實在路由守衛中,只有next()
是放行,其他的諸如:next('/logon') 、 next(to) 或者 next({ ...to, replace: true })
都不是放行,而是:中斷當前導航,執行新的導航
可以這么理解:
next()
是放行,但是如果next()
里有參數的話,next()
就像被重載一樣,就有了不同的功能。
而對於上面說的中斷當前導航,執行新的導航打個比方:
現在我有一個守衛,在守衛中我使用next('/logon')
,肯定有同學認為是會直接跳轉到/logon
路由:
beforeEach((to, from, next) => { next('/logon') }
然而年輕人不講武德,執行時需要這么看:
beforeEach((to, from, next) => { beforeEach(('/logon', from, next) => { beforeEach(('/logon', from, next) => { beforeEach(('/logon', from, next) => { beforeEac... // 一直循環下去...... , 因為我們沒有使用 next() 放行 } } } }
如果把這個守衛改一下,當我在地址欄輸入/home
時
beforeEach((to, from, next) => { if(to.path === '/home') { next('/logon') } else { // 如果要去的地方不是 /home , 就放行 next() } }
我本來要去/home
路由,因此執行了第一次 beforeEach((to, from, next)
但是這個路由守衛中判斷了如果要去的地方是'/home'
,就執行next('/logon')
,
所以想要訪問/home
可以這么看
beforeEach((to, from, next) => { beforeEach(('/logon', from, next) => { next() // 現在要去的地方不是 /home , 因此放行 } }
注意:重點就在這,next('/logon')
不是說直接去/logon
路由,而是中斷(不是CPU的那個中斷!VUE中的中斷就是此時不會執行router.afterEach(() => {}
)這一次路由守衛的操作,又進入一次路由守衛,就像嵌套一樣,一層路由守衛,然后又是一層路由守衛,此時路由守衛進入到第二層時,to.path
已經不是/home
了,這個時候才執行next()
放行操作。
正以為如此很多人在使用動態添加路由addRoutes()
會遇到下面的情況:
在addRoutes()
之后第一次訪問被添加的路由會白屏,這是因為剛剛addRoutes()
就立刻訪問被添加的路由,然而此時addRoutes()
沒有執行結束,因而找不到剛剛被添加的路由導致白屏。因此需要從新訪問一次路由才行。
該如何解決這個問題 ?
此時就要使用next({ ...to, replace: true })
來確保addRoutes()
時動態添加的路由已經被完全加載上去。
next({ ...to, replace: true })
中的replace: true
只是一個設置信息,告訴VUE本次操作后,不能通過瀏覽器后退按鈕,返回前一個路由。
因此next({ ...to, replace: true })
可以寫成next({ ...to })
,不過你應該不希望用戶在addRoutes()
還沒有完成的時候,可以點擊瀏覽器回退按鈕搞事情吧。
其實next({ ...to })
的執行很簡單,它會判斷:
如果參數to
不能找到對應的路由的話,就再執行一次beforeEach((to, from, next)
直到其中的next({ ...to})
能找到對應的路由為止。
也就是說此時addRoutes()
已經完成啦,找到對應的路由之后,接下來將執行前往對應路由的beforeEach((to, from, next)
,因此需要用代碼來判斷這一次是否就是前往對應路由的beforeEach((to, from, next)
,如果是,就執行next()
放行。
如果守衛中沒有正確的放行出口的話,會一直next({ ...to})
進入死循環 !!!
因此你還需要確保在當addRoutes()
已經完成時,所執行到的這一次beforeEach((to, from, next)
中有一個正確的next()
方向出口。
因此想實現動態添加路由的操作的話,代碼應該是這樣的:
router.beforeEach((to, from, next) => { const token = sessionStorage.getItem('access_token') // 存在 token 說明已經登錄 if (token) { // 登錄過就不能訪問登錄界面,需要中斷這一次路由守衛,執行下一次路由守衛,並且下一次守衛的to是主頁' if (to.path === '/login') { next({ path: '/' }) } // 保存在store中路由不為空則放行 (如果執行了刷新操作,則 store 里的路由為空,此時需要重新添加路由) if (store.getters.getRoutes.length || to.name != null) { //放行 next() } else { // 將路由添加到 store 中,用來標記已添加動態路由 store.commit('ADD_ROUTER', '需要添加的路由') router.addRoutes('需要添加的路由') // 如果 addRoutes 並未完成,路由守衛會一層一層的執行執行,直到 addRoutes 完成,找到對應的路由 next({ ...to, replace: true }) } } else { // 未登錄時,注意 :在這里也許你的項目不只有 logon 不需要登錄 ,register 等其他不需要登錄的頁面也需要處理 if (to.path !== '/logon') { next({ path: '/logon' }) } else { next() } }
https://blog.csdn.net/qq_41912398/article/details/109231418