查看: 2560|回复: 3

vue-admin动态路由实现:后端菜单与addRoutes配置

[复制链接]
发表于 前天 14:00 | 显示全部楼层 |阅读模式
vue-admin 后台管理模板中,菜单通常由后端按角色控制并返回,前端拿到数据后再生成路由和侧边栏。本文按原文思路整理动态路由落地时需要改动的几个位置:router/index.js、Vuex permission 模块、全局路由拦截和 Sidebar 渲染。

一、精简 router/index.js 的静态路由
把 constantRoutes 中写死的静态路由删掉,只保留 login、404 等公共页面。其他业务路由不再写死在前端,而是后面通过接口获取。这样前端只负责公共页面,权限菜单由后端决定。

二、用 Vuex 的 permission 模块管理菜单
如果没有 store/modules/permission.js 就创建。该模块用 Vuex 状态管理保存菜单信息,最后把菜单渲染出去。核心状态有两个:routes 是拼接完成、需要暴露出去的路由;addRoutes 是后端返回的路由。SET_ROUTES 中把 constantRoutes 与后端路由拼接,并保存后端路由。
  1. // store/modules/permission.js
  2. import { constantRoutes } from '@/router'
  3. import { getRouter } from '@/api/user'
  4. const state = {
  5.   routes: [],
  6.   addRoutes: []
  7. }
  8. const mutations = {
  9.   SET_ROUTES: (state, routes) => {
  10.     state.addRoutes = routes
  11.     state.routes = constantRoutes.concat(routes)
  12.   }
  13. }
  14. const actions = {
  15.   generateRoutes({ commit }, roles) {
  16.     return new Promise(resolve => {
  17.       commit('SET_ROUTES', getRouter())
  18.       resolve(getRouter())
  19.     })
  20.   }
  21. }
  22. export default {
  23.   namespaced: true,
  24.   state,
  25.   mutations,
  26.   actions
  27. }
复制代码
然后在 getter 中暴露 permission_routes,并在 store 入口注册 permission 模块:
  1. permission_routes: state => state.permission.routes
  2. import permission from './modules/permission'
复制代码
原文示例中 generateRoutes 接收了 roles 参数,但核心逻辑里直接调用 getRouter() 获取后端路由。实际项目如果接口是异步的,需要结合 Promise 或 async/await 处理返回值;角色过滤最终应以后端返回结果为准。

三、在 src/permission.js 中拦截路由并添加动态路由
路由拦截阶段调用 permission/generateRoutes,拿到后端路由后,调用 router.addRoutes,并通过 next({ ...to, replace: true }) 重新进入目标路由,避免动态路由尚未挂载导致跳转异常。
  1. store.dispatch('permission/generateRoutes').then(newRouter => {
  2.   router.addRoutes(filterRouter(newRouter))
  3.   next({ ...to, replace: true })
  4. })
复制代码
后端返回的路由不能直接给 vue-router 使用,需要遍历处理 component。若 component 等于字符串 "Layout",替换为导入的 Layout 组件;否则交给 loadComponent 做路由懒加载。存在 children 时递归处理。
  1. import Layout from '@/layout'
  2. const filterRouter = (router) => {
  3.   const res = []
  4.   router.forEach(a => {
  5.     if (a.component === 'Layout') {
  6.       a.component = Layout
  7.     } else {
  8.       a.component = loadComponent(a.component)
  9.     }
  10.     if (a.children && a.children.length > 0) {
  11.       a.children = filterRouter(a.children)
  12.     }
  13.     res.push(a)
  14.   })
  15.   return res
  16. }
  17. const loadComponent = (path) => {
  18.   // 路由懒加载(参数不能以 / 开头)
  19.   return (resolve) => require([`@/views/${path}.vue`], resolve)
  20. }
复制代码
这里要注意 component 路径格式。静态路由通常写成:
  1. component: () => import('@/views/table/index')
复制代码
后端返回时要写成:
  1. component: "table/index"
复制代码
也就是不能以斜杠 / 开头。@/views/ 前缀由前端在 require 中拼接,路径才能正确解析。如果后端直接返回 "/table/index",懒加载路径就会出错。

四、修改 Sidebar 导航菜单渲染
在 src/layout/components/Sidebar/index.vue 中,把菜单数据源改为 permission_routes:
  1. <!-- 动态路由 -->
  2. <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
复制代码
permission_routes 来自前面的 Vuex getter,这样侧边栏就会根据后端返回并转换后的路由渲染菜单。

五、关键点与适用场景
1. constantRoutes 只留下公共页面,业务菜单走后端接口。
2. 后端菜单需要经过 filterRouter 转换 component,Layout 组件单独处理,子路由递归处理。
3. loadComponent 使用 require 做路由懒加载,传入路径不能带前导斜杠。
4. 动态添加路由后使用 next({ ...to, replace: true }),保证路由挂载完成后再次进入目标地址。
5. 该方案适合 vue-admin 这类需要按角色返回菜单的后台管理系统;菜单和路由的控制权在后端,前端只负责格式转换与渲染。

以上实现点均围绕原文的 router、Vuex permission、全局路由拦截和 Sidebar 渲染展开。
回复

使用道具 举报

发表于 前天 19:00 | 显示全部楼层

Re: vue-admin动态路由实现:后端菜单与addRoutes配置

整理得挺清楚的,四个改动点串起来后思路顺多了。constantRoutes 只留公共页面、业务菜单完全由后端决定,这个方向确实更灵活,后面加权限也不用反复改前端静态路由。 我自己看下来最容易出问题的还是 filterRouter 里 component 的处理:后端返回 Layout 时要替换成真正的 Layout 组件,其他路径像 table/index 不能带前面的斜杠,不然拼接 @/views/ 后懒加载路径会错;有 children 时也要记得递归处理。另外 generateRoutes 那里如果 getRouter 是异步接口,直接 commit 可能会拿到空数据,最好等接口返回后再 resolve。路由拦截里 addRoutes 之后用 next({ ...to, replace: true }) 也很关键,不然动态路由还没挂上就跳转容易异常。 Sidebar 改成 permission_routes 这点也很重要,菜单和路由走同一份数据,后面维护起来会省心很多。你最后 loadComponent 那段好像没写完,期待补全,整体已经很实用了。
回复 支持 反对

使用道具 举报

发表于 前天 19:10 | 显示全部楼层

Re: vue-admin动态路由实现:后端菜单与addRoutes配置

这个整理很实用,基本上把 vue-admin 动态路由要改的几个位置都串起来了。constantRoutes 只保留 login、404 这类公共页面,业务菜单完全由后端返回,这样前端权限维护会轻很多;permission 模块里 routes 和 addRoutes 分开存,SET_ROUTES 再把 constantRoutes 和后端路由拼起来,最后 getter 暴露 permission_routes 给 Sidebar 用,整条链路很清晰。 我比较关注两个容易出问题的点:一是 getRouter 如果是异步接口,generateRoutes 里直接 commit 同步结果肯定不行,得用 Promise 或 async/await 拿到数据再 resolve;二是后端返回的 component 路径,像 table/index 这种不能带开头的斜杠,Layout 又要单独替换成导入的 Layout,children 还得递归处理。路由拦截里 addRoutes 之后用 next 带上 to 和 replace 重新进入,也确实能避免动态路由还没挂载导致的跳转异常。感谢分享,这几个位置照着排查应该能省不少时间。
回复 支持 反对

使用道具 举报

发表于 前天 19:20 | 显示全部楼层

Re: vue-admin动态路由实现:后端菜单与addRoutes配置

整理得挺清楚,按 router/index.js、Vuex permission、全局路由拦截和 Sidebar 四个位置来讲,动态路由落地时不容易乱。constantRoutes 只留公共页面、业务菜单交给后端返回这个思路挺实用,filterRouter 里对 Layout 单独替换、children 递归处理,还有 loadComponent 路径不能以斜杠开头,都是实际配置时很容易踩的坑。generateRoutes 那里提到 roles 参数和 getRouter 异步处理也很关键,直接当成同步返回值确实可能出问题。Sidebar 改用 permission_routes 后,菜单和路由就能共用同一份数据源,维护起来方便很多。末尾 loadCompon 好像没写完,如果方便的话可以补全懒加载那段,整体就更完整了。感谢分享。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-12 12:30 , Processed in 0.020842 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部