Vue + Vite 项目中动态路由刷新失效的解决方案
在基于 Vue3 + Vite 的中后台项目中,动态路由 + 登录鉴权 是常见的权限控制方案。然而,我们往往会遇到一个恼人的问题:刷新页面后,动态路由失效,页面跳转失败,控制台中 to.matched 为空,或者提示找不到对应路由。
一、问题描述
1.动态路由流程简述
我们的项目采用后端控制菜单 + 前端动态生成路由的方式。用户登录后:
-
发送登录请求,获取 token;
-
请求用户权限与菜单数据;
-
根据菜单生成动态路由,并通过 router.addRoute() 添加到路由表;
-
页面跳转至第一个可访问页面。
2.刷新场景下的问题
在开发环境(以 Vite 为例)中,刷新页面时会触发以下一系列重置流程:
-
所有运行状态被清空;
-
重新从 vite.config.ts 中的入口文件(通常是 main.ts)加载;
-
执行 Vue 应用初始化流程,包括挂载路由等。
此时路由表中仅有静态路由,原本通过登录后 addRoute() 添加的动态路由已经不存在。
此时若刷新的是一个动态页面路径,例如:https://example.com/layout/system/user,那么 Vue Router 会立即尝试匹配该路径,但此时你还没有注册这条路由,因此
- to.matched.length === 0
- 页面报错或白屏
- 控制台提示找不到组件等
二、解决方案
为了解决上述问题,我们从两个方面入手:
1. 路由数据持久化
创建 useMenuStore 来管理后端返回的菜单列表:
export const useMenuStore = defineStore('menu', {
state: () => {
return {
menuList: [],
firstMenu: '',
}
},
persist: {
enabled: true,
storage: sessionStorage,
}
})
当用户登录成功后,将后端返回的菜单原封不动存入 menuList,使用动态路由生成函数(例如 generateRoutes(menuList))遍历该列表生成前端路由对象,通过 router.addRoute(‘layout’, route) 将路由添加到主框架的子路由中。
使用 pinia-plugin-persistedstate 插件将 useUserStore 和 useMenuStore 持久化,确保刷新后可以从 localStorage 或 sessionStorage 中恢复数据。
2. 在合适的时机添加动态路由
在首次刷新时,重新注册动态路由。为了避免每次跳转都执行添加操作,引入 isRefresh 标志位,在 router/permission.ts 中添加:
let isRefresh = true
router.beforeEach((to, from, next) => {
// 刷新且token有效才可以
if(!refresh && useUserStore.token){
refresh = true
dynamicRoute(useMenuStore().menuList)
// 关键点:重新跳转一次,确保路由匹配
return next({...to,replace:true})
}
}
问题大致解决思路就是这样,具体代码要根据项目不同做修改
2988

被折叠的 条评论
为什么被折叠?



