尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Vue3 动态路由 + v-permission 按钮级权限:菜单从后端来,按钮一把锁

发布时间:2026/9/29 4:54:42

资讯中心
01
ARTICLE

Vue3 动态路由 + v-permission 按钮级权限:菜单从后端来,按钮一把锁

Vue3 动态路由 + v-permission 按钮级权限:菜单从后端来,按钮一把锁
导读招聘后台管理系统企业管理员、求职顾问、超管三个角色看到的菜单不一样页面上能点的按钮也不一样。最初是前端写死v-ifrole admin后来角色多了、权限细了代码里全是这种判断改一次权限要动十几个文件。这次重构把菜单做成后端返回、路由动态注册、按钮用指令控制一次说清踩过的坑。Vue3 动态路由 v-permission 按钮级权限菜单从后端来按钮一把锁先说背景。管理系统登录后后端根据用户角色返回一份权限数据能访问哪些菜单路由 path 列表、每个菜单下能操作哪些按钮权限码列表。前端要做两件事按权限动态注册路由菜单只显示有权限的按钮级控制没权限的按钮直接消失或禁用。一、路由守卫里动态注册后端登录接口返回{token:xxx,menus:[{path:/jobs,name:Jobs,component:jobs/index,meta:{title:职位管理,perms:[job:list,job:audit]}},{path:/users,name:Users,component:users/index,meta:{title:用户管理,perms:[user:list]}}]}前端维护一张组件映射表把后端给的 component 字符串映射到实际组件后端给不了组件引用只能给字符串前端必须有一张表对应constmodulesimport.meta.glob(../views/**/*.vue)functionloadView(component){// ../views/jobs/index.vue - 模块returnmodules[../views/${component}.vue]}functionbuildRoutes(menus){returnmenus.map(m({path:m.path,name:m.name,component:loadView(m.component),meta:m.meta}))}路由守卫在登录后拉取菜单、动态注册// router/index.jsrouter.beforeEach(async(to){conststoreuseUserStore()if(!store.token){return{name:Login,query:{redirect:to.fullPath}}}// 关键只拉一次避免每次跳转都重新注册if(!store.menusLoaded){constmenusawaitfetchMenus()store.setMenus(menus)menus.forEach(mrouter.addRoute(m))store.menusLoadedtrue// 重新进入当前路由让新注册的路由生效return{...to,replace:true}}})addRoute后必须return { ...to, replace: true }重新进入一次否则首次登录后访问的路由还是白屏——动态路由刚注册Vue Router 还没感知。二、按钮级权限用指令菜单控制路由按钮控制操作。写一个v-permission指令权限码列表存在 Pinia 里// directives/permission.jsimport{useUserStore}from/stores/userconstpermission{mounted(el,binding){conststoreuseUserStore()constpermsbinding.value// 例如 [job:audit]consthasPermperms.some(pstore.perms.includes(p))if(!hasPerm){// 没权限直接移除元素el.parentNodeel.parentNode.removeChild(el)}}}app.directive(permission,permission)模板里这样用审核职位 删除角色多、权限码多的场景后端返回的权限码数组要扁平化前端只判断有没有这个码不做角色逻辑权限变更全部由后端配置驱动。三、菜单渲染从数据来侧边栏菜单不再手写直接遍历 store 里的 menus后端加了新页面前端只要补views目录 组件映射表里有对应文件菜单自动出现。权限维护从改代码变成了改配置。踩坑记录刷新页面白屏路由守卫死循环现象登录后一切正常一刷新F5页面白屏控制台报No match found for location。排查过程刷新后 Pinia 状态清空store.menusLoaded变成 false守卫里重新拉菜单、重新 addRoute。问题在拉菜单的接口是异步的addRoute 还没执行完路由解析已经开始找不到匹配路由直接白屏。更坑的是我一开始在beforeEach里加了个next()结果 addRoute 后 next() 继续走路由表没更新完无限循环报错。定位思路查了 Vue Router 4 的文档和 issue核心是守卫里用返回值代替 nextVue Router 4 推荐并且在 addRoute 之后return { ...to, replace: true }让路由重新解析一次。同时用store.menusLoaded做幂等避免重复 addRoute重复注册同名路由会告警虽然不致命但不干净。最终解决守卫里 addRoute 后 replace 重新进入登录页跳首页时也确保菜单先加载完再进。另外我把菜单接口的 loading 状态暴露给页面白屏期间显示骨架屏体验上也顺了不少。这之后刷新、直接输 URL 进深链都没再白屏。可直接复用的要点动态路由组件用import.meta.glob映射后端只传 component 字符串。addRoute后return { ...to, replace: true }重进一次防白屏。menusLoaded标志位做幂等别每次跳转都重复注册路由。按钮权限用自定义指令v-permission权限码扁平化后端配置驱动。菜单渲染遍历后端数据别手写权限变更不动前端代码。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。