VUE 路由守衛 next() / next({ ...to, replace: true })區別

語言: CN / TW / HK

其實在路由守衛中,只有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) => { beforeEach(('/logon', from, next) => { next() // 現在要去的地方不是 /home , 因此放行 } } 重點就在這,next('/logon')不是說直接去/logon路由,而是中斷這一次路由守衛的操作,又進入一次路由守衛,就像巢狀一樣,一層路由守衛,然後又是一層路由守衛,此時路由守衛進入到第二層時,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() } }

```