查看: 297|回复: 0

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

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
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 渲染展开。
回复

使用道具 举报

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

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

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

官方核心成员

关注微信公众号

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

GMT+8, 2026-9-10 16:38 , Processed in 0.021542 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部