动态路由刷新恢复


动态路由注册之后,页面刷新会丢失运行时添加的路由,如果不处理,就会出现明明有权限但是刷新后进入 404 的问题

上一篇记录了动态菜单和动态路由的生成。

但是动态路由还有一个很常见的问题:刷新页面后路由丢失。

因为 router.addRoute 添加的是运行时路由,浏览器一刷新,内存里面的路由就没有了。

如果用户刚好停留在一个动态页面,比如:

1
#/demo/table

刷新之后,如果没有重新注册动态路由,就会匹配不到页面。

思路

解决这个问题的思路其实很简单:

  1. 登录后保存 token
  2. 登录后保存菜单
  3. 菜单持久化到本地
  4. 刷新页面时先判断 token
  5. 有 token 但是动态路由未注册时,先恢复动态路由
  6. 路由注册完后重新进入当前地址

这样刷新之后,页面就能重新匹配到动态路由。

路由标记

我这里用了一个变量记录动态路由是否已经注册:

1
let dynamicRouteReady = false;

刚进页面的时候肯定是 false

只要执行过动态路由注册,就改成 true

注册动态路由

动态路由统一挂载到 layout 下面:

1
2
const dynamicParentName = 'layout';
let removeDynamicRouteList = [];

注册的时候先重置旧路由,再重新添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export function setupDynamicRoutes() {
resetRouter();

const store = routerStore();

store.addRouter((route) => {
if (!route?.name || router.hasRoute(route.name)) {
return;
}

removeDynamicRouteList.push(router.addRoute(dynamicParentName, route));
});

dynamicRouteReady = true;
}

这里需要注意 router.addRoute 会返回一个删除当前路由的方法。

所以我把它保存到 removeDynamicRouteList 中,退出登录或者权限变化时可以清掉。

重置路由

重置的时候直接调用之前保存的方法:

1
2
3
4
5
export function resetRouter() {
removeDynamicRouteList.forEach((removeRoute) => removeRoute());
removeDynamicRouteList = [];
dynamicRouteReady = false;
}

这样比手动判断哪些路由需要删除更稳一点。

路由守卫

真正处理刷新恢复的地方是在全局前置守卫里面。

核心逻辑是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
router.beforeEach((to, from, next) => {
const userStore = userInfoStore();
const hasToken = !!userStore.token;

if (!hasToken) {
next('/');
return;
}

if (!dynamicRouteReady) {
setupDynamicRoutes();
redirectToCurrentPath(to, next);
return;
}

next();
});

也就是说,只要用户有 token,但是动态路由还没准备好,就先注册动态路由。

为什么要重新进入当前地址

动态路由注册之后,不能简单地 next()

因为当前这次匹配是在动态路由注册之前发生的,当时 Vue Router 还不知道这个地址对应哪个组件。

所以注册完之后,需要重新进入一次当前路径:

1
2
3
4
5
6
7
8
const redirectToCurrentPath = (to, next) => {
next({
path: to.path,
query: to.query,
hash: to.hash,
replace: true
});
};

这里使用 replace: true,避免刷新恢复时多增加一条历史记录。

登录页处理

还有一种情况是用户已经登录了,但是访问登录页。

这种时候也需要先恢复动态路由,然后跳转到第一个有权限的菜单。

1
2
3
4
5
6
7
8
9
10
11
12
13
if (whiteList.includes(to.path)) {
if (hasToken) {
if (!dynamicRouteReady) {
setupDynamicRoutes();
}

next(routerStore().getFirstMenuPath() || '/home');
return;
}

next();
return;
}

这样用户刷新登录页或者手动进入登录页,都不会卡在不正确的状态。

退出登录

退出登录或者 token 失效时,需要清掉几类数据:

  1. token
  2. 用户信息
  3. 菜单
  4. 按钮权限
  5. 动态路由

如果只清 token,不清动态路由,切换账号后可能会看到上一个账号的路由。

所以退出时一定要调用 resetRouter

总结

动态路由刷新恢复的关键点有两个:

  1. 菜单和权限要持久化
  2. 刷新后要在路由守卫中重新注册动态路由

注册完之后,还要重新进入当前地址,让 Vue Router 用新的路由表重新匹配页面。

以上就是我对动态路由刷新恢复的一些理解,如有错误,欢迎大佬指出。

-------------本文结束感谢您的阅读-------------