9.7 KiB
9.7 KiB
首页路由梳理说明
🔍 问题分析
原来的问题
首页在多个地方被设置,导致路由混乱和错误:
-
src/utils/uiTool.js的getRoutes方法- 接收了
HomePage参数但没有使用 children初始化为空数组- 尝试查找不存在的
homeRoute,返回undefined - 使用
undefined导致路由错误
- 接收了
-
src/index.js的install方法- 调用
getRoutes创建路由 - 传入了
HomePage但没有被使用
- 调用
-
demo-project/src/main.js的mounted钩子- 又调用了
setAuthorityMenus重新设置菜单 - 导致路由被重复设置
- 又调用了
错误信息
vue-router.esm.js:1396 Uncaught TypeError: Cannot read properties of undefined (reading 'path')
[vuex] unknown action type: getSysTitle
[vuex] unknown getter: sysFormModel
✅ 解决方案
设计原则
- 单一职责:每个方法只负责一件事
- 避免重复:路由只在一个地方创建和设置
- 清晰的流程:首页设置流程清晰可追踪
新的首页设置流程
应用启动
↓
框架 install 方法
↓
调用 getRoutes 创建主路由
↓
创建默认首页路由 (/home)
↓
检查 localStorage 中的权限菜单
↓
如果有权限菜单,合并到主路由
↓
创建 VueRouter 实例
↓
应用启动完成
↓
用户登录
↓
保存权限菜单到 localStorage
↓
刷新页面
↓
重新执行上述流程(此时有权限菜单)
📝 修改内容
1. 修复 src/utils/uiTool.js 的 getRoutes 方法
修改前:
static getRoutes(Main, ParentView, Page404, HomePage) {
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: [] // ❌ 空数组,没有默认首页
}
// ... 后续逻辑尝试使用不存在的 homeRoute
const homeRoute = mainRoute.children.find(r => r.name === 'home') // ❌ undefined
mainRoute.children = [homeRoute, ...curRoutes] // ❌ 使用 undefined
}
修改后:
static getRoutes(Main, ParentView, Page404, HomePage) {
// ✅ 创建默认的首页路由
const defaultHomeRoute = {
path: '/home',
name: 'home',
meta: { title: '首页', notCache: true },
component: HomePage || {
render: h => h('div', { style: { padding: '20px' } }, '欢迎使用管理系统')
}
}
let mainRoute = {
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
meta: { title: '首页', notCache: true },
children: [defaultHomeRoute] // ✅ 包含默认首页
}
// 从 localStorage 读取权限菜单
if (localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined') {
let authorityMenus = JSON.parse(localStorage.authorityMenus) || []
if (authorityMenus && authorityMenus.length > 0) {
let menus = uiTool.transformTree(authorityMenus)
let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404)
// 检查权限路由中是否有 home
const hasHome = curRoutes.some(r => r.name === 'home')
if (hasHome) {
// 如果权限路由中有 home,使用权限路由的 home
mainRoute.children = curRoutes
} else {
// 如果权限路由中没有 home,保留默认 home 并添加其他路由
mainRoute.children = [defaultHomeRoute, ...curRoutes]
}
}
}
return mainRoute
}
改进点:
- ✅ 使用传入的
HomePage参数 - ✅ 创建默认的首页路由
- ✅ 正确处理权限菜单的合并
- ✅ 避免使用
undefined
2. 简化 demo-project/src/main.js
修改前:
window.rootVue = new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// ❌ 重复设置权限菜单
this.$store.dispatch('user/setAuthorityMenus', {
Main: AdminFramework.Main,
ParentView: AdminFramework.ParentView,
Page404: AdminFramework.Page404
})
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
})
修改后:
window.rootVue = new Vue({
el: '#app',
router: AdminFramework.router,
store: AdminFramework.store,
render: h => h(App),
mounted() {
AdminFramework.uiTool.setRem()
// ✅ 只获取系统标题,不重复设置菜单
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
})
改进点:
- ✅ 移除了重复的
setAuthorityMenus调用 - ✅ 路由只在框架初始化时创建一次
- ✅ 登录后通过刷新页面重新加载路由
3. 修复 Vuex 模块命名空间问题
修改的文件:
src/components/main/main.vuesrc/components/main/components/user/user.vue
修改前:
// main.vue
...mapGetters({
sysFormModel: 'sysFormModel', // ❌ 缺少模块前缀
menuList: 'menuList',
userName: 'userName',
userAvator: 'avatorImgPath'
})
// user.vue
...mapActions(['handleLogOut']) // ❌ 缺少模块前缀
修改后:
// main.vue
...mapGetters({
sysFormModel: 'app/sysFormModel', // ✅ 添加模块前缀
menuList: 'user/menuList',
userName: 'user/userName',
userAvator: 'user/avatorImgPath'
})
// user.vue
...mapActions('user', ['handleLogOut']) // ✅ 指定模块
🎯 完整的首页路由流程
首次访问(未登录)
1. 用户访问 http://localhost:8080
↓
2. 框架初始化
↓
3. getRoutes 创建主路由
- localStorage 中没有 authorityMenus
- 使用默认首页路由
↓
4. 路由配置:
{
path: '/',
component: Main,
children: [
{ path: '/home', name: 'home', component: HomePage }
]
}
↓
5. 显示登录页面
登录流程
1. 用户输入用户名密码
↓
2. 调用登录接口
↓
3. 保存 token 和用户信息
↓
4. 调用 setAuthorityMenus
- 尝试获取权限菜单(可能失败)
- 使用默认菜单配置
- 保存到 localStorage
↓
5. 刷新页面 (window.location.reload())
↓
6. 重新执行首次访问流程
- 此时 localStorage 中有 authorityMenus
- 根据权限菜单生成路由
登录后访问
1. 用户访问 http://localhost:8080
↓
2. 框架初始化
↓
3. getRoutes 创建主路由
- localStorage 中有 authorityMenus
- 解析权限菜单
- 生成权限路由
↓
4. 路由配置:
{
path: '/',
component: Main,
children: [
{ path: '/home', name: 'home', component: HomePage },
{ path: '/system/user', name: 'sys_user', component: SysUser },
{ path: '/system/role', name: 'sys_role', component: SysRole },
// ... 其他权限路由
]
}
↓
5. 显示系统首页
📊 路由结构
完整的路由树
routes: [
// 登录页面
{
path: '/login',
name: 'login',
component: LoginPage
},
// 主路由
{
path: '/',
name: '主视图',
redirect: '/home',
component: Main,
children: [
// 默认首页
{
path: '/home',
name: 'home',
component: HomePage,
meta: { title: '首页', notCache: true }
},
// 权限路由(从 authorityMenus 生成)
{
path: '/system/user',
name: 'sys_user',
component: SysUser,
meta: { title: '用户管理' }
},
{
path: '/system/role',
name: 'sys_role',
component: SysRole,
meta: { title: '角色管理' }
},
// ... 更多权限路由
]
},
// 错误页面
{
path: '/401',
name: 'error_401',
component: Page401
},
{
path: '/500',
name: 'error_500',
component: Page500
},
{
path: '*',
name: 'error_404',
component: Page404
}
]
✅ 验证清单
功能验证
- ✅ 首次访问显示登录页面
- ✅ 登录成功后跳转到首页
- ✅ 首页正确显示
- ✅ 左侧菜单正确显示
- ✅ 系统标题正确显示
- ✅ 用户名正确显示
- ✅ 页面跳转正常
- ✅ 刷新页面后状态保持
错误修复
- ✅ 修复了
Cannot read properties of undefined (reading 'path')错误 - ✅ 修复了
[vuex] unknown action type: getSysTitle错误 - ✅ 修复了
[vuex] unknown getter: sysFormModel错误 - ✅ 修复了首页路由重复设置的问题
💡 最佳实践
1. 路由创建原则
- 单一入口:路由只在框架初始化时创建一次
- 数据驱动:根据 localStorage 中的数据动态生成路由
- 默认兜底:始终提供默认的首页路由
2. 权限菜单处理
- 登录时保存:登录成功后保存权限菜单到 localStorage
- 启动时读取:应用启动时从 localStorage 读取权限菜单
- 刷新更新:登录后刷新页面,重新生成路由
3. 避免的陷阱
- ❌ 不要在多个地方创建或修改路由
- ❌ 不要在 mounted 钩子中重复设置菜单
- ❌ 不要忘记处理 undefined 的情况
- ❌ 不要忘记 Vuex 模块的命名空间
🎉 总结
修复的问题
- ✅ 首页路由正确创建
- ✅ 权限菜单正确合并
- ✅ 避免了重复设置
- ✅ 修复了 Vuex 命名空间问题
- ✅ 流程清晰可维护
代码改进
- 减少复杂度:移除了重复的菜单设置逻辑
- 提高可读性:流程更清晰,易于理解
- 增强健壮性:正确处理各种边界情况
- 符合规范:遵循 Vue 和 Vuex 的最佳实践
首页路由梳理完成! 🎉
现在路由创建流程清晰、简洁、可靠。