# 首页路由梳理说明 ## 🔍 问题分析 ### 原来的问题 首页在多个地方被设置,导致路由混乱和错误: 1. **`src/utils/uiTool.js` 的 `getRoutes` 方法** - 接收了 `HomePage` 参数但没有使用 - `children` 初始化为空数组 - 尝试查找不存在的 `homeRoute`,返回 `undefined` - 使用 `undefined` 导致路由错误 2. **`src/index.js` 的 `install` 方法** - 调用 `getRoutes` 创建路由 - 传入了 `HomePage` 但没有被使用 3. **`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 ``` ## ✅ 解决方案 ### 设计原则 1. **单一职责**:每个方法只负责一件事 2. **避免重复**:路由只在一个地方创建和设置 3. **清晰的流程**:首页设置流程清晰可追踪 ### 新的首页设置流程 ``` 应用启动 ↓ 框架 install 方法 ↓ 调用 getRoutes 创建主路由 ↓ 创建默认首页路由 (/home) ↓ 检查 localStorage 中的权限菜单 ↓ 如果有权限菜单,合并到主路由 ↓ 创建 VueRouter 实例 ↓ 应用启动完成 ↓ 用户登录 ↓ 保存权限菜单到 localStorage ↓ 刷新页面 ↓ 重新执行上述流程(此时有权限菜单) ``` ## 📝 修改内容 ### 1. 修复 `src/utils/uiTool.js` 的 `getRoutes` 方法 **修改前**: ```javascript 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 } ``` **修改后**: ```javascript 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` **修改前**: ```javascript 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: '' }) } }) ``` **修改后**: ```javascript 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.vue` - `src/components/main/components/user/user.vue` **修改前**: ```javascript // main.vue ...mapGetters({ sysFormModel: 'sysFormModel', // ❌ 缺少模块前缀 menuList: 'menuList', userName: 'userName', userAvator: 'avatorImgPath' }) // user.vue ...mapActions(['handleLogOut']) // ❌ 缺少模块前缀 ``` **修改后**: ```javascript // 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 模块的命名空间 ## 🎉 总结 ### 修复的问题 1. ✅ 首页路由正确创建 2. ✅ 权限菜单正确合并 3. ✅ 避免了重复设置 4. ✅ 修复了 Vuex 命名空间问题 5. ✅ 流程清晰可维护 ### 代码改进 - **减少复杂度**:移除了重复的菜单设置逻辑 - **提高可读性**:流程更清晰,易于理解 - **增强健壮性**:正确处理各种边界情况 - **符合规范**:遵循 Vue 和 Vuex 的最佳实践 --- **首页路由梳理完成!** 🎉 现在路由创建流程清晰、简洁、可靠。