动态路由刷新恢复
动态路由注册之后,页面刷新会丢失运行时添加的路由,如果不处理,就会出现明明有权限但是刷新后进入 404 的问题
上一篇记录了动态菜单和动态路由的生成。
但是动态路由还有一个很常见的问题:刷新页面后路由丢失。
因为 router.addRoute 添加的是运行时路由,浏览器一刷新,内存里面的路由就没有了。
如果用户刚好停留在一个动态页面,比如:
1 | #/demo/table |
刷新之后,如果没有重新注册动态路由,就会匹配不到页面。
思路
解决这个问题的思路其实很简单:
- 登录后保存 token
- 登录后保存菜单
- 菜单持久化到本地
- 刷新页面时先判断 token
- 有 token 但是动态路由未注册时,先恢复动态路由
- 路由注册完后重新进入当前地址
这样刷新之后,页面就能重新匹配到动态路由。
路由标记
我这里用了一个变量记录动态路由是否已经注册:
1 | let dynamicRouteReady = false; |
刚进页面的时候肯定是 false。
只要执行过动态路由注册,就改成 true。
注册动态路由
动态路由统一挂载到 layout 下面:
1 | const dynamicParentName = 'layout'; |
注册的时候先重置旧路由,再重新添加:
1 | export function setupDynamicRoutes() { |
这里需要注意 router.addRoute 会返回一个删除当前路由的方法。
所以我把它保存到 removeDynamicRouteList 中,退出登录或者权限变化时可以清掉。
重置路由
重置的时候直接调用之前保存的方法:
1 | export function resetRouter() { |
这样比手动判断哪些路由需要删除更稳一点。
路由守卫
真正处理刷新恢复的地方是在全局前置守卫里面。
核心逻辑是:
1 | router.beforeEach((to, from, next) => { |
也就是说,只要用户有 token,但是动态路由还没准备好,就先注册动态路由。
为什么要重新进入当前地址
动态路由注册之后,不能简单地 next()。
因为当前这次匹配是在动态路由注册之前发生的,当时 Vue Router 还不知道这个地址对应哪个组件。
所以注册完之后,需要重新进入一次当前路径:
1 | const redirectToCurrentPath = (to, next) => { |
这里使用 replace: true,避免刷新恢复时多增加一条历史记录。
登录页处理
还有一种情况是用户已经登录了,但是访问登录页。
这种时候也需要先恢复动态路由,然后跳转到第一个有权限的菜单。
1 | if (whiteList.includes(to.path)) { |
这样用户刷新登录页或者手动进入登录页,都不会卡在不正确的状态。
退出登录
退出登录或者 token 失效时,需要清掉几类数据:
- token
- 用户信息
- 菜单
- 按钮权限
- 动态路由
如果只清 token,不清动态路由,切换账号后可能会看到上一个账号的路由。
所以退出时一定要调用 resetRouter。
总结
动态路由刷新恢复的关键点有两个:
- 菜单和权限要持久化
- 刷新后要在路由守卫中重新注册动态路由
注册完之后,还要重新进入当前地址,让 Vue Router 用新的路由表重新匹配页面。
以上就是我对动态路由刷新恢复的一些理解,如有错误,欢迎大佬指出。