一行代码解决Vue异步路由刷新后404的问题
背景/home:项目首页,同步路由/uc/profile:个人信息页,异步路由,登录后根据用户角色展示。/login?redirect=%2Fuc%2Fprofile(%2F是/ 的url转义) :登录页,同步路由,在个人信息页退出登录会进入登录页并携带redirect=/uc/profile,再次登录成功后,直接进入个人信息页项目:基于vue-element-admin,对权限菜单,异步路由,M
背景
/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}`);
}
}
});
效果:
存在的问题:输入错误的路径,例如:/home1,只会显示白屏。
为了处理错误的路径,给路由添加重定向;这是输入/home1可以重定向到404页了;
export const constantRoutes = [
...homeRouter,
{
path: "/404",
component: () => import("@/views/error-page/404"),
hidden: true
},
{ path: "*", redirect: "/404" } // 添加
];
效果:
存在的问题:错误路径可以重定向到404了,但是异步路由页面刷新会重定向到404,并且在异步路由页面退出登录,再登录后自动重定向到异步路由的页面也会404;
这时的from和to如下,from变成了null,to是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事件,不需要判定路径是否为异步
更多推荐
所有评论(0)