Vue使用addRouter()动态生成三级菜单的问题

本文详细介绍了在Vue中如何使用addRouter动态生成三级菜单栏的过程。通过递归过滤异步路由表,根据用户角色权限生成菜单,确保了菜单结构的灵活性与安全性。特别关注二级路由组件设置及路径配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

标题记录一次vue使用addRouter动态生成三级菜单栏的问题

1.addRouter()里面需要一个固定格式的数组:例如

import { asyncRoutes, constantRoutes } from '@/router'
/* Layout */
import Layout from '@/layout'
/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles, parentModules) {
  const res = []

  parentModules.forEach(parentModule => {
    var tmp = {}
    tmp.path = parentModule.parentTargetUrl
   
    tmp.component = Layout
    tmp.name = parentModule.parentTargetUrl.substr(1)
    tmp.meta = {}
    tmp.meta.title = parentModule.parentModuleName
    tmp.meta.icon = 'dashboard'
    tmp.meta.roles = roles
    tmp.children = []
    
    parentModule.modules.forEach(module => {
     
      // XXXListPage
      var childrenTmpListPage = {}
      var childrenTmpEditPage = {}
      //childrenTmpListPage.path = '/' + module.targetName + 'ListPage'
      childrenTmpListPage.name = module.targetName + 'ListPage'
      childrenTmpListPage.meta = {}
      childrenTmpListPage.meta.title = module.moduleName
      childrenTmpListPage.meta.icon = 'dashboard'
      childrenTmpListPage.meta.roles = roles
      //childrenTmpListPage.component = resolve => require(['@/page/' + module.targetName.charAt(0).toUpperCase() + module.targetName.slice(1) + '/list_page'], resolve)
      childrenTmpListPage.path = '/' + module.targetName + 'ListPage'
      
      if(module.childrenModules != null && module.childrenModules != undefined && module.childrenModules != ""){
        childrenTmpListPage.component = Layout

      }else{
        
        childrenTmpListPage.component = resolve => require(['@/page/' + module.targetName.charAt(0).toUpperCase() + module.targetName.slice(1) + '/list_page'], resolve)
        
      }


      childrenTmpListPage.children = []
      // XXXEditPage
      // childrenTmpEditPage.path = '/' + module.targetName + 'EditPage'
      // childrenTmpEditPage.name = module.targetName + 'EditPage'
      // childrenTmpEditPage.meta = {}
      // childrenTmpEditPage.meta.title = module.moduleName
      // childrenTmpEditPage.meta.icon = 'dashboard'
      // childrenTmpEditPage.meta.roles = roles
      // childrenTmpEditPage.hidden = true
      // childrenTmpEditPage.component = resolve => require(['@/page/' + module.targetName.charAt(0).toUpperCase() + module.targetName.slice(1) + '/edit_page'], resolve)
       
      // 三级菜单生成
      var roleChildren = roles
      
      if(module.childrenModules != null && module.childrenModules != undefined && module.childrenModules != ""){
        module.childrenModules.forEach(module =>{
 
          var children2TmpListPage = {}
          var children2TmpEditPage = {}
          //  childrenTmpListPage.path
          children2TmpListPage.path = module.targetName + 'ListPage'
          alert(children2TmpListPage.path)
          children2TmpListPage.name = module.targetName + 'ListPage'
          children2TmpListPage.meta = {}
          children2TmpListPage.meta.title = module.moduleName
          children2TmpListPage.meta.icon = 'dashboard'
          children2TmpListPage.meta.roles = roleChildren
          
          children2TmpListPage.component = resolve => require(['@/page/' + module.targetName.charAt(0).toUpperCase() + module.targetName.slice(1) + '/list_page'], resolve)
          console.log('@/page/' + module.targetName.charAt(0).toUpperCase() + module.targetName.slice(1) + '/list_page')
          childrenTmpListPage.children.push(children2TmpListPage)
          
      })
      
    }
      
      tmp.children.push(childrenTmpListPage)
      // tmp.children.push(childrenTmpEditPage)
    })
    res.push(tmp)
    
  })

  console.log(res)
  return res
}

const state = {
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  }
}

const actions = {
  generateRoutes({ commit }, obj) {
    return new Promise(resolve => {
      let accessedRoutes = filterAsyncRoutes(asyncRoutes, obj.roles, obj.parentModules)
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

  1. 三级路由重点:
    componment: 二级路由不能设置为NULL,必须存在,我设置的就是Layout(引用自@/layout)
    path:路径最前面不能使用"/"

<think>好的,用户的问题是关于在Vue3中如何动态添加路由并生成菜单的示例教程。我需要结合用户提供的三个引用内容,整理出一个清晰的步骤说明,并给出代码示例。同时,根据用户提供的系统级指令,我需要确保回答结构正确,包括正确使用LaTeX格式,生成相关问题,并在引用处添加标识。 首先,我需要回忆Vue3中动态路由的基本概念。动态路由通常是在用户登录后根据权限从后端获取路由数据,然后通过addRoute方法添加到路由器实例中。同时,菜单的生成需要遍历路由配置中的meta字段,提取标题、图标等信息。 接下来,查看用户提供的引用内容: 引用1提到需要定义基础路由表,比如登录页和404页面,提前添加到router中。登录后通过addRoute方法添加从服务器获取的路由,并利用meta字段生成菜单。这里的关键点是基础路由和动态路由的分离,以及meta字段的作用。 引用2给出了一个处理路由组件的方法routerPackag,其中处理了Layout组件和路由懒加载。需要将后端返回的平级路由结构转换为树形结构,以便生成菜单。代码中使用了递归处理子路由,并动态导入组件。 引用3提到在登录后存储路由数据到localStorage,解决刷新丢失路由的问题。需要将后端返回的数据传给初始化路由的方法,并持久化存储。 现在,我需要将这些信息整合成一个步骤化的教程: 1. 创建基础路由:包含无需权限的路由,如登录页、404等。 2. 登录后获取动态路由数据:从后端API获取用户权限对应的路由列表。 3. 处理路由数据:将后端返回的平级结构转换为树形结构,处理组件路径,使用懒加载。 4. 动态添加路由:使用router.addRoute()将处理后的路由添加到路由器实例。 5. 生成菜单:遍历路由的meta信息,生成菜单项,可能需要递归处理嵌套路由。 6. 持久化存储:将路由数据保存到localStorage,防止刷新后丢失。 7. 处理页面刷新:在应用初始化时检查存储的路由数据,重新添加动态路由。 在代码示例部分,需要展示基础路由的定义,处理动态路由的函数,以及菜单生成的组件。同时,注意Vue3的语法,比如使用useRouter钩子,组合式API等。 需要确保LaTeX格式正确,例如变量或代码关键字使用$...$,但可能在这个问题中数学公式较少,不过如果有提及算法或数学相关内容,需注意格式。例如,提到时间复杂度时可能需要使用$O(n \log n)$。 生成的相关问题需要围绕动态路由的实现细节、菜单生成优化、权限控制等。 最后,检查引用标识是否正确添加,每个步骤末尾引用对应的来源。例如,处理路由数据的方法引用自[^2],存储到localStorage引用自[^3]等。 现在需要将这些思考整理成结构化的回答,分步骤说明,并附上代码示例。确保语言简洁,符合中文表达,同时遵循用户的格式要求。</think>### Vue3动态添加路由并生成菜单的步骤示例 #### 1. 定义基础路由表 ```javascript // router/index.js import { createRouter, createWebHistory } from 'vue-router' const staticRoutes = [ { path: '/login', component: () => import('@/views/LoginView.vue'), meta: { hidden: true } }, { path: '/404', component: () => import('@/views/404.vue'), meta: { hidden: true } } ] ``` 定义无需权限即可访问的基础路由,包含登录页和404页面[^1]。 #### 2. 登录后获取动态路由 ```javascript // LoginView.vue const handleLogin = async () => { const res = await api.getRoutes() const dynamicRoutes = processRoutes(res.data) dynamicRoutes.forEach(route => router.addRoute(route)) localStorage.setItem('dynamicRoutes', JSON.stringify(res.data)) } ``` 登录成功后获取后端返回的路由数据,处理后添加到路由器实例[^3]。 #### 3. 路由数据处理函数 ```javascript const processRoutes = (routes) => { return routes.map(route => { if (route.component === 'Layout') { route.component = () => import('@/layout/index.vue') } else { route.component = () => import(`@/views/${route.component}.vue`) } if (route.children) { route.children = processRoutes(route.children) } return route }) } ``` 处理组件路径转换和路由懒加载,递归处理子路由[^2]。 #### 4. 菜单生成组件示例 ```vue <!-- Sidebar.vue --> <template> <div v-for="route in filteredRoutes"> <el-menu-item v-if="!route.children" :index="route.path"> <template #title>{{ route.meta.title }}</template> </el-menu-item> <el-sub-menu v-else :index="route.path"> <template #title>{{ route.meta.title }}</template> <sidebar-item :routes="route.children"/> </el-sub-menu> </div> </template> <script setup> const router = useRouter() const filteredRoutes = router.options.routes.filter( route => !route.meta?.hidden ) </script> ``` 根据路由的meta信息过滤和生成菜单项,支持嵌套路由[^1][^2]。 #### 5. 初始化路由恢复 ```javascript // main.js const initRoutes = () => { const storedRoutes = localStorage.getItem('dynamicRoutes') if (storedRoutes) { const routes = processRoutes(JSON.parse(storedRoutes)) routes.forEach(route => router.addRoute(route)) } } initRoutes() ``` 解决页面刷新后路由丢失问题,初始化时恢复存储的路由配置。 ```mermaid graph TD A[用户登录] --> B[获取动态路由数据] B --> C[数据持久化存储] C --> D[转换路由结构] D --> E[动态添加路由] E --> F[生成菜单] F --> G[路由跳转] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值