解析路由表,生成结构化数据

如果我们需要创建后台管理系统的动态菜单(根据权限显示对应的选项),需要获取路由表的数据信息
想要获取路由表数据,那么有两种方式:

  1. router.options.routes:初始路由列表(无法获取到新增的路由)
  2. router.getRoutes():获取所有 路由记录 的完整列表
    因为方式1的特性有缺陷,因此我们使用方式2获取到路由表

使用router.getRoutes()获取到的路由表信息如下:

[     {         path:/user/info/:id,         name:userInfo,         meta:{             title:userInfo         },         children:[          ]     },     {         path:/user/manage,         meta:{             title:userManage,             icon:personnel-manage         },         children:[          ]     },     {         path:/user/role,         meta:{             title:roleList,             icon:role         },         children:[          ]     },     {         path:/user/permission,         meta:{             title:permissionList,             icon:permission         },         children:[          ]     },     {         path:/user/import,         name:import,         meta:{             title:excelImport         },         children:[          ]     },     {         path:/login,         meta:{          },         children:[          ]     },     {         path:/profile,         name:profile,         meta:{             title:profile,             icon:el-icon-user         },         children:[          ]     },     {         path:/404,         name:404,         meta:{          },         children:[          ]     },     {         path:/401,         name:401,         meta:{          },         children:[          ]     },     {         path:/user,         redirect:/user/manage,         meta:{             title:user,             icon:personnel         },         children:[             {                 path:/user/manage,                 meta:{                     title:userManage,                     icon:personnel-manage                 }             },             {                 path:/user/role,                 meta:{                     title:roleList,                     icon:role                 }             },             {                 path:/user/permission,                 meta:{                     title:permissionList,                     icon:permission                 }             },             {                 path:/user/info/:id,                 name:userInfo,                 meta:{                     title:userInfo                 }             },             {                 path:/user/import,                 name:import,                 meta:{                     title:excelImport                 }             }         ]     } ] 

由上,可以看出,它是一个一级路由与二级路由位于数组同一层级的数据结构,这不符合我们的需求,我们需要的是一个一级路由内包括二级路由的数据结构,类似于树结构的数据结构,它需要符合如下特点:

  1. 满足该条件 meta && meta.title && meta.icon
  2. 一级路由二级路由应该是树形嵌套
[     {         path:/profile,         name:profile,         meta:{             title:profile,             icon:el-icon-user         },         children:[          ]     },     {         path:/user,         redirect:/user/manage,         meta:{             title:user,             icon:personnel         },         props:{             default:false         },         children:[             {                 path:/user/manage,                 meta:{                     title:userManage,                     icon:personnel-manage                 },                 children:[                  ]             },             {                 path:/user/role,                 meta:{                     title:roleList,                     icon:role                 },                 children:[                  ]             },             {                 path:/user/permission,                 meta:{                     title:permissionList,                     icon:permission                 },                 children:[                  ]             }         ],         instances:{          },         leaveGuards:{          },         updateGuards:{          },         enterCallbacks:{          },         components:{             default:{                 __scopeId:data-v-13877386,                 __hmrId:13877386,                 __file:src/layout/index.vue             }         }     },     {         path:/article,         redirect:/article/ranking,         meta:{             title:article,             icon:article         },         props:{             default:false         },         children:[             {                 path:/article/ranking,                 meta:{                     title:articleRanking,                     icon:article-ranking                 },                 children:[                  ]             },             {                 path:/article/create,                 meta:{                     title:articleCreate,                     icon:article-create                 },                 children:[                  ]             }         ],         instances:{          },         leaveGuards:{          },         updateGuards:{          },         enterCallbacks:{          },         components:{             default:{                 __scopeId:data-v-13877386,                 __hmrId:13877386,                 __file:src/layout/index.vue             }         }     } ] 

因此,我们需要对它进行解析
utils/route.js

import path from 'path'  /**  * 返回所有子路由  */ const getChildrenRoutes = routes => {   const result = []   routes.forEach(route => {     if (route.children && route.children.length > 0) {       result.push(...route.children)     }   })   return result } /**  * 处理脱离层级的路由:某个一级路由为其他子路由,则剔除该一级路由,保留路由层级  * @param {*} routes router.getRoutes()  */ export const filterRouters = routes => {   const childrenRoutes = getChildrenRoutes(routes)   return routes.filter(route => {     return !childrenRoutes.find(childrenRoute => {       return childrenRoute.path === route.path     })   }) }  /**  * 判断数据是否为空值  */ function isNull(data) {   if (!data) return true   if (JSON.stringify(data) === '{}') return true   if (JSON.stringify(data) === '[]') return true   return false } /**  * 根据 routes 数据,返回对应 menu 规则数组  */ export function generateMenus(routes, basePath = '') {   const result = []   // 遍历路由表   routes.forEach(item => {     // 不存在 children && 不存在 meta 直接 return     if (isNull(item.meta) && isNull(item.children)) return     // 存在 children 不存在 meta,进入迭代     if (isNull(item.meta) && !isNull(item.children)) {       result.push(...generateMenus(item.children))       return     }     // 合并 path 作为跳转路径     const routePath = path.resolve(basePath, item.path)     // 路由分离之后,存在同名父路由的情况,需要单独处理     let route = result.find(item => item.path === routePath)     if (!route) {       route = {         ...item,         path: routePath,         children: []       }        // icon 与 title 必须全部存在       if (route.meta.icon && route.meta.title) {         // meta 存在生成 route 对象,放入 arr         result.push(route)       }     }      // 存在 children 进入迭代到children     if (item.children) {       route.children.push(...generateMenus(item.children, route.path))     }   })   return result } 

生成符合动态menu要求的结构化数据:

import { computed } from 'vue' import { useRouter } from 'vue-router' import { filterRouters, generateMenus } from '@/utils/route'  const router = useRouter() // 获取符合动态menu菜单需要的结构化路由表数据 const routes = computed(() => {   const filterRoutes = filterRouters(router.getRoutes())   return generateMenus(filterRoutes) })