6.5 KiB
6.5 KiB
Ether 项目前端路由最佳实践
概述
本文档总结了 Ether 项目前端路由开发中的最佳实践,以及常见问题和解决方案。
路由架构设计
1. 路由分层结构
路由层级:
├── 公开路由 (Public Routes)
│ ├── /login - 登录页
│ └── /no-project - 无项目提示页
│
├── 布局路由 (Layout Route)
│ └── / (Layout)
│ ├── /space-node - 空间节点管理
│ ├── /mdm/projects - 项目管理
│ ├── /mdm/visitors - 访客管理
│ └── ... 其他业务页面
│
└── 404 路由
└── /* - 匹配所有未定义路由
2. 动态路由生成机制
// 1. 定义组件映射表
const dynamicRouteComponents: Record<string, () => Promise<any>> = {
"Mdm/projects": () => import("../views/mdm/project/index.vue"),
"Mdm/visitors": () => import("../views/mdm/visitor/index.vue"),
// ...
};
// 2. 根据后端菜单数据生成路由
function generateRoutesFromMenus(menus: MenuInfo[]): RouteRecordRaw[] {
return menus.map(menu => ({
path: menu.menuPath, // 如: "/mdm/visitors"
name: menu.componentName, // 如: "Mdm/visitors"
component: dynamicRouteComponents[menu.componentName],
meta: {
title: menu.permissionName,
icon: menu.menuIcon,
},
}));
}
// 3. 动态添加到路由表
menuRoutes.forEach(route => {
router.addRoute("Layout", {
path: route.path.substring(1), // 移除开头的 "/"
name: route.name,
component: route.component,
meta: route.meta,
});
});
常见问题与解决方案
问题 1: 菜单点击后页面不跳转
症状: 点击侧边栏菜单,页面没有切换,URL 不变。
根本原因:
- 菜单点击使用
router.push({ name: key }),但动态路由的name可能未正确注册 - 路由守卫中动态添加路由后,使用
name导航可能找不到对应路由
解决方案:
// ❌ 错误方式:使用 name 导航
const handleMenuClick = ({ key }: { key: string }) => {
router.push({ name: key }); // 可能找不到路由
};
// ✅ 正确方式:使用 path 导航
const handleMenuClick = ({ key }: { key: string }) => {
const menu = findMenuByComponentName(menus, key);
if (menu?.menuPath) {
router.push(menu.menuPath); // 使用 path 更可靠
}
};
问题 2: 动态路由添加后刷新 404
症状: 动态添加路由后可以访问,但刷新页面后显示 404。
根本原因:
- 动态路由只在路由守卫中添加一次,刷新后需要重新添加
- 404 路由优先级问题
解决方案:
// 1. 确保每次路由守卫都检查并添加路由
router.beforeEach(async (to, from, next) => {
if (!permissionStore.isInitialized) {
await permissionStore.fetchUserPermissions();
// 重新生成并添加路由
const menuRoutes = generateRoutesFromMenus(permissionStore.menus);
menuRoutes.forEach(route => {
const existing = router.getRoutes().find(r => r.name === route.name);
if (!existing) {
router.addRoute("Layout", route);
}
});
// 重新导航
next({ ...to, replace: true });
return;
}
next();
});
// 2. 404 路由最后添加,确保优先级最低
router.addRoute({
path: "/:pathMatch(.*)*",
name: "NotFound",
component: () => import("../views/404/index.vue"),
});
问题 3: 路由名称冲突
症状: 控制台警告路由名称已存在。
根本原因:
- 多次添加相同 name 的路由
- 热更新时重复添加
解决方案:
// 添加前检查是否已存在
menuRoutes.forEach(route => {
const existingRoute = router.getRoutes().find(r => r.name === route.name);
if (!existingRoute) {
router.addRoute("Layout", route);
}
});
问题 4: 路由路径格式不一致
症状: 菜单数据和路由配置的路径不匹配。
根本原因:
- 后端返回的
menuPath包含前导/,但动态添加时需要移除 - 路由配置中 path 格式不统一
解决方案:
// 统一路径格式
const normalizePath = (path: string): string => {
// 确保以 / 开头
if (!path.startsWith('/')) {
path = '/' + path;
}
// 移除尾部 /
return path.replace(/\/$/, '') || '/';
};
// 动态添加时移除前导 /
router.addRoute("Layout", {
path: route.path.substring(1), // "/mdm/visitors" -> "mdm/visitors"
...
});
数据流设计
菜单数据结构
interface MenuInfo {
id: string;
permissionCode: string; // 权限编码: "mdm:visitor:menu"
permissionName: string; // 显示名称: "访客管理"
menuPath: string; // 路由路径: "/mdm/visitors"
menuIcon?: string; // 图标: "UserAddOutlined"
componentName: string; // 组件名: "Mdm/visitors"
parentId?: string; // 父菜单ID
sortOrder: number; // 排序
children?: MenuInfo[]; // 子菜单
}
关键映射关系
| 后端字段 | 前端用途 | 示例 |
|---|---|---|
componentName |
路由 name / 菜单 key | Mdm/visitors |
menuPath |
路由 path | /mdm/visitors |
permissionName |
页面标题 / 菜单标签 | 访客管理 |
menuIcon |
菜单图标 | UserAddOutlined |
开发规范
1. 新增页面步骤
- 创建页面组件:
src/views/{module}/{page}/index.vue - 注册路由映射: 在
src/router/index.ts的dynamicRouteComponents中添加 - 配置后端权限: 在数据库中添加菜单和权限数据
- 验证路由: 确保
componentName和menuPath匹配
2. 路由配置检查清单
componentName在dynamicRouteComponents中有对应映射menuPath格式统一(以/开头)- 路由
name唯一,不与其他路由冲突 - 动态路由添加前检查是否已存在
3. 调试技巧
// 查看所有已注册路由
console.log(router.getRoutes());
// 检查特定路由是否存在
const route = router.getRoutes().find(r => r.name === 'Mdm/visitors');
console.log(route);
// 监听路由变化
router.beforeEach((to, from) => {
console.log('Navigating from', from.path, 'to', to.path);
});
相关文件
src/router/index.ts- 路由配置和动态路由生成src/views/layout/index.vue- 布局组件和菜单处理src/stores/permission.ts- 权限状态和菜单数据
更新记录
| 日期 | 更新内容 | 作者 |
|---|---|---|
| 2026-02-10 | 初始版本,总结路由问题和解决方案 | AI Assistant |