天天看點

一行代碼解決Vue異步路由重新整理後404的問題

背景

/home:項目首頁,同步路由

/uc/profile:個人資訊頁,異步路由,登入後根據使用者角色展示。

/login?redirect=%2Fuc%2Fprofile(%2F是 / 的url轉義) :登入頁,同步路由,在個人資訊頁登出會進入登入頁并攜帶redirect=/uc/profile,再次登入成功後,直接進入個人資訊頁

項目:基于vue-element-admin,對權限菜單,異步路由,Mock檔案都已經寫好了。隻需要根據需求修改就可以!

問題:

最開始項目沒有配置重定向404(路由沒有 {path:"*",redirect:"/"} ),在/uc/profile頁面重新整理可以重新顯示,并且登出後重新登入也可以再次顯示頁面。

此時路由配置:

// 同步路由
export const constantRoutes = [
  ...homeRouter,
  {
    path: "/404",
    component: () => import("@/views/error-page/404"),
    hidden: true
  }
];
// 異步路由(通過後端擷取或者前端篩選添加)
export const asyncRoutes = [
  {
    path: "/uc",
    component: Layout,
    children: [
      {
        path: "profile",
        component: () => import("@/views/manage/profile"),
        name: "Profile",
        meta: { title: "個人資訊", icon: "el-icon-user" }
      },
      { path: "*", redirect: "/404", hidden: true }
    ]
  }
];
// beforeEach
router.beforeEach(async (to, from, next) => {
  const hasToken = getToken();
  if (hasToken) {
    if (to.path === "/login") {
      next();
    } else {
      const hasRoles = store.getters.roles && store.getters.roles.length > 0;
      if (hasRoles) {
        next();
      } else {
        try {
          const { roles } = await store.dispatch("user/getInfo");
          const accessRoutes = await store.dispatch(
            "permission/generateRoutes",
            roles
          );
          router.addRoutes(accessRoutes);
          next({ ...to, replace: true });
        } catch (error) {
          await store.dispatch("user/resetToken");
          next(`/login?redirect=${to.path}`);
        }
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next();
    } else {
      next(`/login?redirect=${to.path}`);
    }
  }
});
           

效果:

一行代碼解決Vue異步路由重新整理後404的問題

存在的問題:輸入錯誤的路徑,例如:/home1,隻會顯示白屏。 

為了處理錯誤的路徑,給路由添加重定向;這是輸入/home1可以重定向到404頁了;

export const constantRoutes = [
  ...homeRouter,
  {
    path: "/404",
    component: () => import("@/views/error-page/404"),
    hidden: true
  },
  { path: "*", redirect: "/404" } // 添加
];
           

效果:

一行代碼解決Vue異步路由重新整理後404的問題

存在的問題:錯誤路徑可以重定向到404了,但是異步路由頁面重新整理會重定向到404,并且在異步路由頁面登出,再登入後自動重定向到異步路由的頁面也會404;

這時的from和to如下,from變成了null,to是404

一行代碼解決Vue異步路由重新整理後404的問題

其他解決方案:

網上看了不少部落格,基本都是使用sessionStorage去在監聽unload事件,在重新整理的時候去報存異步頁面的路徑;在beforeEach中addRoute之後,判斷sessionStorage,去跳轉到異步頁面;

// App.vue
watch: {
    $route: () => {
      window.addEventListener("beforeunload", () => { // unload也一樣
        sessionStorage.setItem("tp", window.location.pathname);
      });
    },
  },
-----------------------
// beforeEach
.....
router.addRoutes(accessRoutes);
let p = sessionStorage.getItem("tp");
if (p.startsWith('/uc')) { // 判斷是否為異步路由
   sessionStorage.removeItem("tp");
   router.replace(p);
} else {
   sessionStorage.removeItem("tp");
   next({ ...to });
}
....
           

這樣解決異步路由的問題,但是又産生了其他問題。

你需要在擷取到sessionStorage之後去判斷這個路徑是不是異步的(如果不判斷的話,你在頁面通過a的href是無法跳轉的,并且你在/home頁下故意輸入錯誤路徑/home1,并不會重定向到404,會重新回到/home頁面等許多問題)。

最終方案

beforeEach的to參數,有一個redirectedFrom屬性,可以根據這個屬性來進行判定。

// beforeEach
...
router.addRoutes(accessRoutes);
if (to.redirectedFrom) {
   router.replace(to.redirectedFrom);
} else {
   next({ ...to });
}
...
           
這個方式,不需要監聽unload事件,不需要判定路徑是否為異步