多业务模块下的 Vue 路由系统设计与复用逻辑

94 阅读2分钟

一、前言:当项目越来越大,路由系统就成了“协作痛点”

广告平台发展初期,所有模块路由写在一个 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+ 模块。