前端菜单权限方案
方案一:前端全量配置路由表 + 后端返回权限码
思路
所有可能的路由都在前端
router
中静态配置好(就像你现在这样)。登录后,后端返回当前用户的菜单权限(通常是一个权限
code
列表)。前端根据权限码过滤掉无权访问的路由,生成最终的可访问菜单。
优点
路由结构清晰,开发时有完整的路由提示和类型支持。
不依赖后端返回路由结构,前端可独立开发和调试。
性能好,减少一次菜单结构的接口解析。
缺点
每次新增菜单都需要前端改代码并发版。
如果菜单结构变化频繁,前端维护成本高。
方案二:后端返回菜单/路由结构,前端动态生成路由
思路
登录后,后端直接返回当前用户可访问的菜单树(包含
path
、component
、meta
等信息)。前端用
router.addRoute()
动态注册路由。菜单渲染直接用后端返回的数据。
优点
菜单和权限完全由后端控制,前端无需改代码即可调整菜单结构。
多端(Web、App、小程序)可共用一套菜单权限数据。
缺点
前端需要做动态组件加载(
import()
),并处理找不到组件的情况。路由类型提示和 IDE 自动补全会缺失。
如果后端返回的路由数据有误,前端可能直接挂掉。
建议
如果你的系统菜单变化不频繁(比如 ERP、后台管理系统),推荐方案一: 前端全量配置路由,后端只返回权限码,前端过滤展示。 这样开发体验好,调试方便,出错率低。
如果你的系统菜单变化频繁(比如 SaaS 平台,不同客户菜单差异大),推荐方案二: 后端返回菜单树,前端动态注册路由,真正做到菜单和权限后端可配。
混合方案(很多企业在用)
前端维护一个路由组件映射表(
path
→component
)。后端返回菜单结构(只包含
path
、meta
等),前端用映射表找到对应组件并动态注册。这样既能后端控制菜单,又能保证组件路径可控。
// 路由组件映射表
const componentMap = {'dashboard': () => import('@/views/Dashboard/index.vue'),'system/user': () => import('@/views/System/User.vue'),// ...
}// 动态注册
menus.forEach(menu => {router.addRoute('Layout', {path: menu.path,name: menu.name,component: componentMap[menu.component]})
})
方案一和方案二速度上性能比较
性能对比
对比项 | 方案一:前端全量配置 + 权限过滤 | 方案二:后端返回菜单/路由结构 |
---|---|---|
首屏速度 | 较快。路由表已经在打包时编译进前端代码,进入系统时只需拿到权限码做一次本地过滤即可。 | 稍慢。登录后需要额外请求菜单数据,再根据数据动态注册路由,才能进入页面。 |
网络请求 | 登录接口 + 权限接口(可合并),不需要额外的菜单结构接口。 | 登录接口 + 菜单接口(必需),多一次网络往返。 |
渲染延迟 | 几乎无延迟,过滤完成即可渲染。 | 需要等菜单接口返回并处理完动态路由后才能渲染。 |
打包体积 | 稍大(包含所有路由组件),但可配合懒加载减少首屏体积。 | 可能稍小(只加载基础路由),但动态加载组件时会有额外延迟。 |
总结
速度优先 → 方案一更快,因为路由表和组件都已经在前端准备好,进入系统时只做一次本地过滤。
灵活性优先 → 方案二更灵活,菜单结构改动不需要前端发版,但首屏会慢一点。
为什么混合方案比方案二能提升速度那?
组件路径提前确定,避免运行时查找失败
方案二:后端返回的
component
通常是字符串(如"system/user"
),前端需要在运行时用import()
去拼接路径并加载,这个过程会触发 Webpack 的动态模块查找,范围大时会生成一个很大的动态 chunk map,解析和匹配都要时间。混合方案:前端事先维护一个
componentMap
(key → import函数
),直接用componentMap[menu.component]
获取组件加载函数,跳过了运行时路径匹配,Webpack 只打包实际用到的模块,按需加载更快。
路由注册逻辑更轻量
方案二:后端返回的菜单数据需要先做一轮“数据清洗 + 动态 import + 异步注册”,这一步必须等接口返回后才能开始。
混合方案:后端只返回菜单结构(不含复杂组件路径解析),前端拿到数据后直接用映射表匹配组件并注册,省去了动态路径解析的耗时。
首屏渲染提前启动
方案二:首屏必须等菜单接口返回 + 动态 import 完成后才能渲染主框架。
混合方案:因为组件映射表在打包时就存在,首屏可以先渲染 Layout 框架,菜单接口返回后再补充路由,不会阻塞主框架渲染。
打包优化更好
方案二:动态路径 import 可能导致 Webpack 打包出一个大而全的 chunk(因为它无法静态分析具体会用到哪些组件)。
混合方案:映射表是静态的,Webpack 能精确分割 chunk,按需加载,减少首屏下载体积。
总结
混合方案的提速点在于:
路径解析提前到编译期,减少运行时动态匹配
组件按需打包,避免大 chunk
首屏可并行渲染,减少等待时间