一、前言:当项目越来越大,路由系统就成了“协作痛点”
广告平台发展初期,所有模块路由写在一个 routes.ts 中:
- 多达上百条路由,查找困难
- 权限判断逻辑散落在各个页面
- 多角色用户共享代码,但显示逻辑混乱
我在重构阶段推动实现了“模块解耦 + 动态挂载 + 权限驱动 + 路由复用”的方案。
二、路由分模块设计
我们按业务域划分路由模块:
// routes/ad.ts
export const adRoutes = [
{
path: '/ad-plan',
meta: { title: '广告计划', permission: 'ad:plan:view' },
component: () => import('@/views/ad/plan/index.vue')
},
{
path: '/ad-material',
meta: { title: '素材管理', permission: 'ad:material:view' },
component: () => import('@/views/ad/material/index.vue')
}
]
总入口统一加载:
import { adRoutes } from './ad'
import { reportRoutes } from './report'
export const allRoutes = [...adRoutes, ...reportRoutes]
三、支持按角色动态挂载
登录后根据权限动态注册路由:
const setupRoutes = (permissions: string[]) => {
const matchedRoutes = allRoutes.filter(r => permissions.includes(r.meta.permission))
matchedRoutes.forEach(r => router.addRoute(r))
}
防止用户输入非法路径:
router.beforeEach((to, _, next) => {
if (!router.hasRoute(to.name)) return next('/403')
next()
})
四、路由懒加载 + 分块打包优化
component: () => import(/* webpackChunkName: "ad-plan" */ '@/views/ad/plan/index.vue')
Vite 会自动生成按模块划分的 chunk,提高初次加载性能。
五、Layout 层级嵌套路由结构
统一布局入口:
{
path: '/',
component: () => import('@/layout/index.vue'),
children: [...业务模块路由]
}
支持横向 tab、左侧菜单自动渲染。
六、支持多项目复用的路由模板结构
封装配置化入口:
interface AppModuleRouteConfig {
moduleName: string
routes: RouteRecordRaw[]
basePath: string
permissions: string[]
}
注册入口统一函数:
export const registerModuleRoutes = (configs: AppModuleRouteConfig[]) => {
configs.forEach(cfg => {
cfg.routes.forEach(route => {
if (cfg.permissions.includes(route.meta.permission)) {
router.addRoute({ ...route, path: cfg.basePath + route.path })
}
})
})
}
七、权限导航菜单生成机制
根据路由表与权限生成菜单:
const generateMenu = (routes: RouteRecordRaw[]) => {
return routes.filter(r => userPermissions.includes(r.meta.permission))
.map(r => ({ label: r.meta.title, path: r.path }))
}
支持多层级菜单(递归)+ Icon 配置化绑定
八、路由与 tabs、面包屑的联动实现
- 每次跳转记录 tab 状态(name + path)
- tabs 从路由表中反查 title 和 key
- 面包屑通过 parent path 构造
const currentTabs = reactive<RouteRecordRaw[]>([])
router.afterEach(to => {
if (!currentTabs.find(t => t.path === to.path)) {
currentTabs.push(to)
}
})
九、典型问题处理
问题1:用户切换角色后,旧路由未清空
➡️ 登出时调用 resetRouter() 并重新挂载权限路由
问题2:权限配置变动,前端不刷新仍能访问旧页面?
➡️ 服务端下发版本号 + 本地 route hash 校验自动重载
十、总结
在多业务 + 多角色 + 多项目的中后台系统中,路由系统的可扩展性决定了整体协作效率。
我设计的这套“分模块注册 + 动态挂载 + 权限驱动 + 配置复用”的路由系统,已支撑广告平台平稳迭代 40+ 模块。