vue——路由守衛beforeEach,next(), next('/'), next({...to, repalce: true})說明及實例問題


參考: 手摸手,帶你用vue擼后台 系列二(登錄權限篇) - SegmentFault 思否

       VUE 路由守衛 next() / next({ ...to, replace: true }) / next(‘/‘) 說明_cimo的博客-CSDN博客_replace: true

      導航守衛 | Vue Router (vuejs.org)

      Error: Redirected when going from “/login?redirect=%2Fdashboard“ to “/dashboard“ via a navigation_Tom__cy的博客-CSDN博客

一. 說明

導航守衛官方文檔:

 

在路由守衛中,只有next()是放行,其他的諸如:next('/login') 、 next(to) 或者 next({ ...to, replace: true })都不是放行,而是:中斷當前導航,執行新的導航

 

例1:

beforeEach((to, from, next) => {
  next('/login')
}

實際執行流程:

beforeEach((to, from, next) => {
  beforeEach(('/login', from, next) => {
       beforeEach(('/login', from, next) => {
            beforeEach(('/login', from, next) => {
                beforeEac...  // 一直循環下去...... , 因為沒有使用 next() 放行
         }
      }
  }
}

 

例2:

beforeEach((to, from, next) => {
   if(to.path === '/home') {
       next('/login')
   } else {
    // 如果要去的地方不是 /home , 就放行
       next()
   }
}

訪問 '/home' ,執行第一次 beforeEach,但是這個路由守衛中判斷了如果要去的地方是'/home',就執行next('/login'),流程如下:

beforeEach((to, from, next) => {
   beforeEach(('/login', from, next) => {
     next()  // 現在要去的地方不是 /home , 因此放行
   }
}

重點,next('/login')不是說直接去/login路由,而是中斷(不是CPU的那個中斷!VUE中的中斷就是此時不會執行router.afterEach(() => {})這一次路由守衛的操作,

   又進入一次路由守衛,就像嵌套一樣,一層路由守衛,然后又是一層路由守衛,此時路由守衛進入到第二層時,to.path已經不是/home了,這個時候才執行next()放行操作。

 

二. 實例

我的情況:有基礎路由,其余路由,由后端根據用戶權限返回,前端使用addRoutes()動態添加

 

問題1:addRoutes()之后第一次訪問被添加的路由會白屏

原因:此時addRoutes()沒有執行結束,因而找不到剛剛被添加的路由導致白屏。因此需要從新訪問一次路由才行。

解決方案:使用next({ ...to, replace: true })來確保addRoutes()時動態添加的路由已經被完全加載上去(使用next()的話,傳到鈎子函數里的to參數 是添加路由之前的值(這個to的參數是值傳遞),所以不行)

     replace: true 只是一個設置信息,告訴VUE本次操作后,不能通過瀏覽器后退按鈕,返回前一個路由。

     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()方向出口

 

main.js/router.js:

router.beforeEach((to, from, next) => {
  if (store.getters.token) { // 判斷是否有token
    if (to.path === '/login') { // 登錄過就不能訪問登錄界面,需要中斷這一次路由守衛,執行下一次路由守衛,並且下一次守衛的to是主頁
      next({ path: '/' });
    } else {
      if (store.getters.addRoutes.length === 0) { // 判斷是否已生成過動態路由
        store.dispatch('generateRoute').then(res => { // 異步操作,獲取用戶的權限,與已設置好的路由進行對比,篩選出用戶可訪問的動態路由,存放在store的addRoutes變量中
          router.addRoutes(store.getters.addRouters) // 動態添加可訪問路由表
          next({ ...to, replace: true }) // hack方法 確保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
        }).catch(err => {
          console.log(err);
        });
      } else {
        next() // 已生成過動態路由,直接進入
      }
    }
  } else { // 未登錄 if (whiteList.indexOf(to.path) !== -1) { // 在免登錄白名單,直接進入
      next();
    } else {
      next('/login'); // 否則全部重定向到登錄頁
    }
  }
});

 

 問題2:登錄后,跳轉首頁控制台會報錯

Error: Redirected when going from "/login" to "/home" via a navigation guard.

原因:

next({ ...to, replace: true })會被認為是一個失敗的navigation(雖然能導航成功,但不再是原來的to),所以login里的repalce()返回一個rejected Promise。

解決方案:

在replace()后面接一個.catch(()=>{})

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM