vben-admin学习(二) 多级路由处理为二级路由

        在之前项目过程中,遇到多级路由时总是要在外层嵌套一层多余的父组件,父组件里面只放一个单独的router-view,之前一直不知道怎么处理。在vben中找到了比较好的解决方案,vben在处理两层以上的多级路由时,会将其展开,转化为二级路由,这样就可以避免不必要的父路由模板。下面是我参照vben复现的过程。

一、对RouteRecordRaw类型进行改造,使其满足我们的要求

import { RouteMeta, RouteRecordRaw } from 'vue-router'
export interface AppRouteMeta extends RouteMeta {
  title: string
  icon?: string
  sn?: number
  hideMenu?: boolean
  permission?: string[]
}

export interface AppRouteRecordRaw
  extends Omit<RouteRecordRaw, 'meta' | 'children' | 'name'> {
  meta: AppRouteMeta
  children?: AppRouteRecordRaw[]
  name: string
}

二、定义基础路由

import { AppRouteRecordRaw } from './type'
import { LAYOUT, PAGE_NOT_FOUND_NAME } from './constants'

export const PAGE_ROOT_ROUTE: AppRouteRecordRaw = {
  path: '/',
  name: 'Root',
  redirect: '/auth',
  component: LAYOUT,
  meta: {
    title: 'Root'
  }
}
export const PAGE_LOGIN_ROUTE: AppRouteRecordRaw = {
  path: '/login',
  name: 'Login',
  component: () => import('@/views/login/index.vue'),
  meta: {
    title: '登录'
  }
}
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
  path: '/:path(.*)*',
  name: PAGE_NOT_FOUND_NAME,
  component: LAYOUT,
  meta: {
    title: 'ErrorPage',
    hideMenu: true
  },
  children: [
    {
      path: '/:path(.*)*',
      name: PAGE_NOT_FOUND_NAME,
      component: () => import('@/views/404/index.vue'),
      meta: {
        title: 'ErrorPage',
        hideMenu: true
      }
    }
  ]
}
export default [PAGE_ROOT_ROUTE, PAGE_LOGIN_ROUTE, PAGE_NOT_FOUND_ROUTE]

三、定义动态路由模块

        我这里以一个四层路由模块为例,我在看源码时,发现vben中会给多级路由的父组件设置为一个Promise,如下,我看来看去没看出来这个的目的是什么,我尝试把这一行去掉,发现对路由也不影响,于是我将其注释掉了。

export const PARENT_LAYOUT_NAME = 'ParentLayout'

export const getParentLayout = (_name?: string) => {
  return () =>
    new Promise((resolve) => {
      resolve({
        name: PARENT_LAYOUT_NAME
      })
    })
}
import { AppRouteRecordRaw } from '../type'
import { getParentLayout, LAYOUT } from '../constants'

const dict: AppRouteRecordRaw = {
  path: '/dict',
  name: 'Dict',
  redirect: '/dict/dict-type/test1',
  component: LAYOUT,
  meta: {
    title: '字典管理',
    icon: 'classify'
  },
  children: [
    {
      path: '/dict/dict-type',
      name: 'DictType',
      redirect: '/dict/dict-type/test1',
      // component: getParentLayout('DictType'),
      meta: {
        title: '字典类型'
      },
      children: [
        {
          path: '/dict/dict-type/test1',
          name: 'Test1',
          // component: getParentLayout('Test1'),
          redirect: '/dict/dict-type/test1/test11',
          meta: {
            title: '测试1'
          },
          children: [
            {
              path: '/dict/dict-type/test1/test11',
              name: 'Test11',
              component: () => import('@/views/dict/dictType/index.vue'),
              meta: {
                title: '测试11'
              }
            },
            {
              path: '/dict/dict-type/test1/test12',
              name: 'Test12',
              component: () => import('@/views/dict/dictType/index1.vue'),
              meta: {
                title: '测试12'
              }
            }
          ]
        },
        {
          path: '/dict/dict-type/test2',
          name: 'Test2',
          component: () => import('@/views/dict/dictType/index1.vue'),
          meta: {
            title: '测试2'
          }
        }
      ]
    },
    {
      path: '/dict/dict-item',
      name: 'DictItem',
      component: () => import('@/views/dict/dictItem/index.vue'),
      meta: {
        title: '字典元素'
      }
    }
  ]
}
export default dict

四、一些初始化路由的操作

import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import setupRouterGuard from './guard'
import { AppRouteRecordRaw } from './type'
import basicRoutes from './basic'
/**
 * 导入所有私有路由模块
 */
const routeModuleList: AppRouteRecordRaw[] = []
const modules = require.context('./modules', true, /\.ts$/)
modules.keys().forEach((key) => {
  const mod = modules(key).default
  routeModuleList.push(mod)
})
const asyncRoutes = [...routeModuleList]
/**
 * 获取初始基础路由名
 */
const WHITE_NAME_LIST: string[] = []
const getRouteNames = (basicRoutes: AppRouteRecordRaw[]) => {
  basicRoutes.forEach((item) => {
    WHITE_NAME_LIST.push(item.name as string)
    getRouteNames(item.children || [])
  })
}
getRouteNames(basicRoutes)
/**
 * 路由初始化
 */
const router = createRouter({
  history: createWebHashHistory(process.env.BASE_URL),
  routes: [...basicRoutes] as RouteRecordRaw[]
})
/**
 * 添加路由守卫
 */
setupRouterGuard(router)

/**
 * 重置路由
 */
const resetRouter = () => {
  // 扁平化的路由
  const routes = router.getRoutes() as unknown as AppRouteRecordRaw[]
  routes.forEach((route) => {
    const { name } = route
    if (name && !WHITE_NAME_LIST.includes(name as string)) {
      router.hasRoute(name) && router.removeRoute(name)
    }
  })
}
export { WHITE_NAME_LIST, asyncRoutes, resetRouter }

export default router

五、将私有路由处理为二级路由

import { cloneDeep } from 'lodash'
import {
  createRouter,
  createWebHashHistory,
  Router,
  RouteRecordRaw
} from 'vue-router'
import { AppRouteRecordRaw } from '../type'

/**
 *
 * @param route 判断是否是多级路由
 * @returns
 */
const isMultipleRoute = (route: AppRouteRecordRaw) => {
  if (
    !route ||
    !Reflect.has(route, 'children') ||
    route.children!.length <= 0
  ) {
    return false
  }
  const children = route.children!
  let flag = false
  for (let i = 0; i < children.length; i++) {
    const child = children[i]
    if (child.children && child.children.length > 0) {
      flag = true
      break
    }
  }
  return flag
}
/**
 *
 * @param route 需要处理的多级路由
 */
const promoteRouteLevel = (route: AppRouteRecordRaw) => {
  let router: Nullable<Router> = createRouter({
    routes: [route as RouteRecordRaw],
    history: createWebHashHistory()
  })
  const routes = router.getRoutes() as unknown as AppRouteRecordRaw[]
  addToChildren(routes, route.children || [], route)
  router = null
  // 子路由的children不需要了
  route.children = (route.children || []).map((item) => {
    item.children = undefined
    return item
  })
}
/**
 *
 * @param routes router.getRoutes()得到的扁平路由
 * @param children 需要处理的多级路由的children
 * @param routeModule 待处理的多级路由的引用
 */
const addToChildren = (
  routes: AppRouteRecordRaw[],
  children: AppRouteRecordRaw[],
  routeModule: AppRouteRecordRaw
) => {
  for (let i = 0; i < children.length; i++) {
    const child = children[i]
    const route = routes.find((item) => item.name === child.name)
    if (!route) continue
    routeModule.children = routeModule.children || []
    if (!routeModule.children.find((item) => item.name === route.name)) {
      routeModule.children.push(route)
    }
    if (child.children && child.children.length > 0) {
      addToChildren(routes, child.children, routeModule)
    }
  }
}
/**
 * 将多级路由转为二级路由
 * @param routes 需要展开的路由组
 * @returns
 */
export const flatMultiLevelRoutes = (routes: AppRouteRecordRaw[]) => {
  const modules = cloneDeep(routes)
  for (let i = 0; i < modules.length; i++) {
    const mod = modules[i]
    if (!isMultipleRoute(mod)) {
      continue
    }
    promoteRouteLevel(mod)
  }
  return modules
}

六、结果测试

import { asyncRoutes } from '@/router/index'

let result = asyncRoutes
result = flatMultiLevelRoutes(result)
console.log(result)

        得到的路由结果如下,已经将所有子路由展开为二级路由。

猜你喜欢

转载自blog.csdn.net/qq_33235279/article/details/130879554
今日推荐