1. 路由系统架构设计
vue-element-plus-admin 项目采用了灵活且强大的路由系统设计,基于 Vue Router 实现,并结合权限系统形成了一个完整的路由控制方案。
1.1 路由系统整体架构
项目路由系统的整体架构可以概括为以下几个部分:
- 路由定义 :在
src/router/index.ts
中定义静态路由和异步路由 - 路由生成 :通过
src/utils/routerHelper.ts
中的辅助函数,根据权限动态生成路由 - 路由守卫 :在
src/permission.ts
中实现路由拦截与权限控制 - 状态管理:使用 Pinia 中的 permission store 管理路由状态
- 组件渲染:基于路由配置渲染菜单和面包屑等导航组件
这种设计将路由配置、权限控制和UI渲染有机结合,实现了灵活的页面访问控制和导航展示。
1.2 路由类型定义
项目使用 TypeScript 定义了详细的路由类型,扩展了 Vue Router 原有的类型定义:
typescript
// types/router.d.ts (简化版)
declare global {
interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
name: string
meta: RouteMeta
component?: Component | string
children?: AppRouteRecordRaw[]
props?: Recordable
fullPath?: string
}
interface AppCustomRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
name: string
meta: RouteMeta
component: string
path: string
redirect?: string
children?: AppCustomRouteRecordRaw[]
}
}
关键扩展:
AppRouteRecordRaw
:扩展了 Vue Router 的RouteRecordRaw
,添加了更丰富的元数据AppCustomRouteRecordRaw
:用于从后端获取的路由结构,组件以字符串形式表示路径
1.3 路由配置结构
在 src/router/index.ts
中,路由被分为两大类:
-
静态路由(constantRouterMap):不需要权限即可访问的路由
typescriptexport const constantRouterMap: AppRouteRecordRaw[] = [ { path: '/', component: Layout, redirect: '/dashboard/analysis', name: 'Root', meta: { hidden: true } }, { path: '/login', component: () => import('@/views/Login/Login.vue'), name: 'Login', meta: { hidden: true, title: t('router.login'), noTagsView: true } }, // 其他基础路由... ]
-
动态路由(asyncRouterMap):需要根据用户权限动态加载的路由
typescriptexport const asyncRouterMap: AppRouteRecordRaw[] = [ { path: '/dashboard', component: Layout, redirect: '/dashboard/analysis', name: 'Dashboard', meta: { title: t('router.dashboard'), icon: 'vi-ant-design:dashboard-filled', alwaysShow: true }, children: [ { path: 'analysis', component: () => import('@/views/Dashboard/Analysis.vue'), name: 'Analysis', meta: { title: t('router.analysis'), noCache: true, affix: true } }, // 其他子路由... ] }, // 更多功能模块路由... ]
1.4 路由元数据(Meta)的应用
路由元数据(Meta)是实现高级路由功能的关键,项目中路由元数据包括:
typescript
interface RouteMeta {
// 标题,用于显示在菜单和面包屑
title: string
// 图标,用于菜单显示
icon?: string
// 是否在菜单中隐藏
hidden?: boolean
// 总是显示根菜单
alwaysShow?: boolean
// 角色列表,控制页面权限
roles?: string[]
// 按钮级权限控制
permission?: string[]
// 是否缓存该页面
noCache?: boolean
// 是否添加到标签视图
noTagsView?: boolean
// 是否固定在标签视图中
affix?: boolean
// 高亮菜单
activeMenu?: string
// 面包屑中是否可见
breadcrumb?: boolean
// 过渡名称
transitionName?: string
// 子菜单是否允许折叠
noCollapse?: boolean
// 不可跳转
canTo?: boolean
// 其他自定义属性...
}
这些元数据不仅用于控制路由的访问权限,还用于指导UI组件(如菜单、面包屑、标签页)的渲染行为。
2. 静态路由与动态路由实现
vue-element-plus-admin 项目支持三种路由生成模式:静态路由、前端动态路由和后端动态路由,这种设计极大地提高了系统的灵活性。
2.1 静态路由模式
静态路由是最简单的路由模式,直接使用预定义的路由配置:
typescript
// src/permission.ts 中的相关代码
if (!appStore.getDynamicRouter) {
await permissionStore.generateRoutes('static')
}
在静态模式下,generateRoutes
方法会直接使用 asyncRouterMap
作为动态路由部分:
typescript
// src/store/modules/permission.ts 中的相关代码
if (type === 'static') {
// 直接读取静态路由表
routerMap = cloneDeep(asyncRouterMap)
}
这种模式适合小型项目或权限结构简单的场景,所有用户看到相同的菜单结构。
2.2 前端动态路由模式
前端动态路由模式基于用户角色在前端过滤路由,实现方式如下:
typescript
// src/permission.ts 中的相关代码
if (appStore.getDynamicRouter) {
appStore.serverDynamicRouter
? await permissionStore.generateRoutes('server', roleRouters as AppCustomRouteRecordRaw[])
: await permissionStore.generateRoutes('frontEnd', roleRouters as string[])
}
前端动态路由的核心是通过 generateRoutesByFrontEnd
函数,根据用户拥有的权限标识过滤路由:
typescript
// src/utils/routerHelper.ts 中的相关代码
export const generateRoutesByFrontEnd = (
routes: AppRouteRecordRaw[],
keys: string[],
basePath = '/'
): AppRouteRecordRaw[] => {
const res: AppRouteRecordRaw[] = []
for (const route of routes) {
// 略过隐藏路由
if (meta.hidden && !meta.canTo) {
continue
}
// 根据用户权限 keys 匹配路由
for (const item of keys) {
if (isUrl(item) && (onlyOneChild === item || route.path === item)) {
data = Object.assign({}, route)
} else {
const routePath = (onlyOneChild ?? pathResolve(basePath, route.path)).trim()
if (routePath === item || meta.followRoute === item) {
data = Object.assign({}, route)
}
}
}
// 递归处理子路由
if (route.children && data) {
data.children = generateRoutesByFrontEnd(
route.children,
keys,
pathResolve(basePath, data.path)
)
}
// 添加到结果集
if (data) {
res.push(data as AppRouteRecordRaw)
}
}
return res
}
这种模式适合权限结构较为稳定,但需要根据用户角色显示不同菜单的场景。
2.3 后端动态路由模式
后端动态路由是最灵活的模式,路由结构完全由后端返回:
typescript
// 后端路由模式
if (appStore.serverDynamicRouter) {
await permissionStore.generateRoutes('server', roleRouters as AppCustomRouteRecordRaw[])
}
后端返回的路由通过 generateRoutesByServer
函数处理:
typescript
export const generateRoutesByServer = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => {
const res: AppRouteRecordRaw[] = []
for (const route of routes) {
const data: AppRouteRecordRaw = {
path: route.path,
name: route.name,
redirect: route.redirect,
meta: route.meta
}
// 动态解析组件
if (route.component) {
const comModule = modules[`../${route.component}.vue`] || modules[`../${route.component}.tsx`]
const component = route.component as string
// 特殊处理布局组件
data.component =
component === '#' ? Layout : component.includes('##') ? getParentLayout() : comModule
}
// 递归处理子路由
if (route.children) {
data.children = generateRoutesByServer(route.children)
}
res.push(data as AppRouteRecordRaw)
}
return res
}
这里的关键是将字符串形式的组件路径解析为实际的组件:
#
表示使用主布局组件##
表示使用父级布局- 其他情况通过动态导入加载组件
后端动态路由模式最为灵活,适合权限结构频繁变动或需要在运行时调整菜单结构的场景。
2.4 路由动态添加机制
无论哪种模式生成的路由,最终都通过 Vue Router 的 addRoute
方法动态添加到路由系统:
typescript
// src/permission.ts
permissionStore.getAddRouters.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw) // 动态添加可访问路由表
})
添加完成后,设置路由初始化标志并跳转到目标页面:
typescript
const redirectPath = from.query.redirect || to.path
const redirect = decodeURIComponent(redirectPath as string)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
permissionStore.setIsAddRouters(true)
next(nextData)
3. 路由守卫与鉴权流程
vue-element-plus-admin 项目通过全局路由守卫实现了完整的鉴权流程,核心代码位于 src/permission.ts
。
3.1 全局前置守卫
项目使用 router.beforeEach
全局前置守卫拦截所有路由导航,实现权限控制:
typescript
router.beforeEach(async (to, from, next) => {
start() // 开始加载进度条
loadStart() // 开始页面加载动画
const permissionStore = usePermissionStoreWithOut()
const appStore = useAppStoreWithOut()
const userStore = useUserStoreWithOut()
// 用户已登录
if (userStore.getUserInfo) {
// 如果访问的是登录页,重定向到首页
if (to.path === '/login') {
next({ path: '/' })
} else {
// 已经添加过动态路由,直接通过
if (permissionStore.getIsAddRouters) {
next()
return
}
// 获取用户角色路由
const roleRouters = userStore.getRoleRouters || []
// 根据配置选择路由生成模式
if (appStore.getDynamicRouter) {
appStore.serverDynamicRouter
? await permissionStore.generateRoutes('server', roleRouters as AppCustomRouteRecordRaw[])
: await permissionStore.generateRoutes('frontEnd', roleRouters as string[])
} else {
await permissionStore.generateRoutes('static')
}
// 动态添加路由
permissionStore.getAddRouters.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw)
})
// 处理重定向
const redirectPath = from.query.redirect || to.path
const redirect = decodeURIComponent(redirectPath as string)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
permissionStore.setIsAddRouters(true)
next(nextData)
}
}
// 用户未登录
else {
// 白名单中的页面允许未登录访问
if (NO_REDIRECT_WHITE_LIST.indexOf(to.path) !== -1) {
next()
} else {
// 其他页面重定向到登录页
next(`/login?redirect=${to.path}`)
}
}
})
鉴权流程的核心逻辑:
- 检查用户是否已登录(有无用户信息)
- 已登录用户:
- 首次访问时动态生成并添加路由
- 后续访问直接通过
- 未登录用户:
- 白名单页面可直接访问
- 其他页面重定向到登录页
3.2 全局后置守卫
项目还使用了全局后置守卫处理路由切换后的操作:
typescript
router.afterEach((to) => {
useTitle(to?.meta?.title as string) // 设置页面标题
done() // 结束进度条
loadDone() // 结束页面加载动画
})
3.3 权限白名单
项目通过常量定义了不需要重定向和不需要重置的路由白名单:
typescript
// src/constants/index.ts
/**
* 不重定向白名单
*/
export const NO_REDIRECT_WHITE_LIST = ['/login']
/**
* 不重置路由白名单
*/
export const NO_RESET_WHITE_LIST = ['Redirect', 'RedirectWrap', 'Login', 'NoFind', 'Root']
这些白名单确保了特定页面(如登录页)能被正确处理,不会陷入重定向循环。
3.4 用户登录与权限获取
用户登录成功后,会设置token并获取用户信息和权限数据:
typescript
// 登录成功后的处理(简化)
const handleActionAfterLogin = async (loginRes: any) => {
// 1. 设置token
userStore.setToken(loginRes.token)
// 2. 获取用户信息
const userInfoRes = await getUserInfoApi()
userStore.setUserInfo(userInfoRes)
// 3. 获取用户路由权限
userStore.setRoleRouters(userInfoRes.routers || [])
// 4. 跳转到首页或重定向页
router.replace(redirect || '/')
}
4. 菜单权限与路由权限联动
vue-element-plus-admin 项目实现了菜单与路由的无缝联动,同时提供了按钮级别的细粒度权限控制。
4.1 菜单生成与路由映射
项目的菜单组件(src/components/Menu
)基于路由配置自动生成,实现了菜单与路由的一一对应:
typescript
// src/components/Menu/src/Menu.vue
const routers = computed(() =>
unref(layout) === 'cutMenu'
? permissionStore.getMenuTabRouters
: permissionStore.getRouters
)
// 渲染菜单项
const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => {
return routers
.filter((v) => !v.meta?.hidden) // 过滤隐藏菜单
.map((v) => {
const meta = v.meta ?? {}
const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v)
const fullPath = isUrl(v.path)
? v.path
: pathResolve(parentPath, v.path)
// 处理只有一个子菜单的情况
if (
oneShowingChild &&
(!onlyOneChild?.children || onlyOneChild?.noShowingChildren) &&
!meta?.alwaysShow
) {
return (
<ElMenuItem
index={onlyOneChild ? pathResolve(fullPath, onlyOneChild.path) : fullPath}
>
{{
default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta)
}}
</ElMenuItem>
)
}
// 处理有多个子菜单的情况
else {
return (
<ElSubMenu
index={fullPath}
teleported
popperClass={unref(menuMode) === 'vertical' ? `${prefixCls}-popper--vertical` : ''}
>
{{
title: () => renderMenuTitle(meta),
default: () => renderMenuItem(v.children!, fullPath) // 递归渲染子菜单
}}
</ElSubMenu>
)
}
})
}
菜单与路由联动的关键点:
- 使用相同的数据源(路由配置)
- 保持路径一致性,确保菜单点击能正确跳转到对应路由
- 根据路由元数据决定菜单的展示形式(图标、标题等)
4.2 面包屑导航
面包屑组件(src/components/Breadcrumb
)同样基于路由配置自动生成,提供了页面层次结构导航:
typescript
// src/components/Breadcrumb/src/Breadcrumb.vue
const getBreadcrumb = () => {
const currentPath = currentRoute.value.matched.slice(-1)[0].path
levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
return node.path === currentPath
})
}
const renderBreadcrumb = () => {
const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
return breadcrumbList.map((v) => {
const disabled = !v.redirect || v.redirect === 'noredirect'
const meta = v.meta
return (
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
{meta?.icon && breadcrumbIcon.value ? (
<>
<Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title || '')}
</>
) : (
t(v?.meta?.title || '')
)}
</ElBreadcrumbItem>
)
})
}
面包屑随着路由变化自动更新:
typescript
watch(
() => currentRoute.value,
(route: RouteLocationNormalizedLoaded) => {
if (route.path.startsWith('/redirect/')) {
return
}
getBreadcrumb()
},
{
immediate: true
}
)
4.3 按钮级权限控制
项目通过自定义指令 v-hasPermi
实现了按钮级的细粒度权限控制:
typescript
// src/directives/permission/hasPermi.ts
const hasPermission = (value: string): boolean => {
const permission = (router.currentRoute.value.meta.permission || []) as string[]
if (!value) {
throw new Error(t('permission.hasPermission'))
}
if (permission.includes(value)) {
return true
}
return false
}
function hasPermi(el: Element, binding: DirectiveBinding) {
const value = binding.value
const flag = hasPermission(value)
if (!flag) {
el.parentNode?.removeChild(el)
}
}
const permiDirective: Directive = {
mounted
}
export const setupPermissionDirective = (app: App<Element>) => {
app.directive('hasPermi', permiDirective)
}
在组件中使用:
html
<!-- 只有拥有 'system:user:add' 权限的用户才能看到这个按钮 -->
<el-button v-hasPermi="'system:user:add'" type="primary">新增用户</el-button>
这个指令检查当前路由的 meta.permission
数组中是否包含指定的权限标识,不包含则从DOM中移除元素,实现了更精细的权限控制。
5. 路由缓存与性能优化
vue-element-plus-admin 项目实现了基于路由的组件缓存机制,避免频繁切换路由导致的组件重复创建和销毁,提升性能和用户体验。
5.1 路由组件缓存实现
项目通过 Vue 内置的 <keep-alive>
和动态缓存列表实现了路由组件缓存:
html
<!-- src/layout/components/AppView.vue -->
<template>
<router-view v-slot="{ Component, route }">
<transition :name="getTransitionName" mode="out-in" appear>
<keep-alive :include="getCaches">
<component :is="Component" :key="getKey" />
</keep-alive>
</transition>
</router-view>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useTagsViewStore } from '@/store/modules/tagsView'
const route = useRoute()
const tagsViewStore = useTagsViewStore()
// 获取需要缓存的组件名称列表
const getCaches = computed(() => {
return tagsViewStore.getCachedViews
})
// 生成组件key,用于强制刷新
const getKey = computed(() => {
return route.path
})
// 获取过渡动画名称
const getTransitionName = computed(() => {
return route?.meta?.transitionName || 'fade'
})
</script>
5.2 缓存控制机制
缓存控制由 tagsView
store 负责,实现了增加、删除和清空缓存的功能:
typescript
// src/store/modules/tagsView.ts
export const useTagsViewStore = defineStore('tagsView', {
state: (): TagsViewState => ({
visitedViews: [],
cachedViews: new Set(), // 使用Set存储缓存视图
selectedTag: undefined
}),
getters: {
getCachedViews(): string[] {
return Array.from(this.cachedViews)
}
},
actions: {
// 添加视图到缓存
addCachedView() {
const cacheMap: Set<string> = new Set()
for (const v of this.visitedViews) {
const item = getRawRoute(v)
const needCache = !item?.meta?.noCache // 根据meta.noCache判断是否需要缓存
if (!needCache) {
continue
}
const name = item.name as string
cacheMap.add(name)
}
if (Array.from(this.cachedViews).sort().toString() === Array.from(cacheMap).sort().toString())
return
this.cachedViews = cacheMap
},
// 删除缓存
delCachedView() {
const route = router.currentRoute.value
const index = findIndex<string>(this.getCachedViews, (v) => v === route.name)
if (index > -1) {
this.cachedViews.delete(this.getCachedViews[index])
}
}
// 其他缓存管理方法...
}
})
缓存控制的关键点:
- 使用
Set
数据结构存储缓存视图名称,确保唯一性 - 根据路由的
meta.noCache
决定是否缓存 - 提供增加、删除、清空等操作方法
5.3 缓存优化策略
项目实现了多种缓存优化策略:
-
选择性缓存 :通过路由元数据
meta.noCache
控制是否缓存组件typescriptconst needCache = !item?.meta?.noCache
-
缓存与标签页联动:关闭标签页时同时清除相应缓存
typescriptdelView(view: RouteLocationNormalizedLoaded) { this.delVisitedView(view) this.addCachedView() // 更新缓存列表 }
-
基于组件名称的缓存 :与 Vue 的
<keep-alive>
机制配合typescriptconst name = item.name as string cacheMap.add(name)
-
路由切换动画 :通过
transitionName
配置路由切换动画,提升用户体验typescriptconst getTransitionName = computed(() => { return route?.meta?.transitionName || 'fade' })
6. 多级路由与面包屑实现
vue-element-plus-admin 项目支持多级路由和面包屑导航,为复杂应用提供了良好的导航结构。
6.1 多级路由的处理
为了更好地支持多级路由,项目实现了路由扁平化处理:
typescript
// src/utils/routerHelper.ts
export const flatMultiLevelRoutes = (routes: AppRouteRecordRaw[]) => {
const modules: AppRouteRecordRaw[] = cloneDeep(routes)
for (let index = 0; index < modules.length; index++) {
const route = modules[index]
if (!isMultipleRoute(route)) {
continue
}
promoteRouteLevel(route)
}
return modules
}
这个函数用于将多级嵌套路由转换为二级路由,适用于某些布局需求:
typescript
// 层级是否大于2
const isMultipleRoute = (route: AppRouteRecordRaw) => {
if (!route || !Reflect.has(route, 'children') || !route.children?.length) {
return false
}
const children = route.children
let flag = false
for (let index = 0; index < children.length; index++) {
const child = children[index]
if (child.children?.length) {
flag = true
break
}
}
return flag
}
// 生成二级路由
const promoteRouteLevel = (route: AppRouteRecordRaw) => {
let router: Router | null = createRouter({
routes: [route as RouteRecordRaw],
history: createWebHashHistory()
})
const routes = router.getRoutes()
addToChildren(routes, route.children || [], route)
router = null
route.children = route.children?.map((item) => omit(item, 'children'))
}
这种路由扁平化处理解决了多级路由在某些UI布局下的展示问题。
6.2 面包屑实现
面包屑组件(src/components/Breadcrumb
)提供了页面导航层次结构的可视化:
typescript
// src/components/Breadcrumb/src/helper.ts
import { RouteRecordNormalized } from 'vue-router'
/**
* 过滤出可用的路由对象
* @param routes - 路由列表
*/
export const filterBreadcrumb = (routes: RouteRecordNormalized[]) => {
const res: RouteRecordNormalized[] = []
for (const route of routes) {
const tmp = { ...route }
if (tmp.meta?.breadcrumb !== false) {
res.push(tmp)
}
}
return res
}
typescript
// src/components/Breadcrumb/src/Breadcrumb.vue
const levelList = ref<AppRouteRecordRaw[]>([])
const menuRouters = computed(() => {
const routers = permissionStore.getRouters
return filterBreadcrumb(routers)
})
const getBreadcrumb = () => {
const currentPath = currentRoute.value.matched.slice(-1)[0].path
levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
return node.path === currentPath
})
}
const renderBreadcrumb = () => {
const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
return breadcrumbList.map((v) => {
const disabled = !v.redirect || v.redirect === 'noredirect'
const meta = v.meta
return (
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
{meta?.icon && breadcrumbIcon.value ? (
<>
<Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title || '')}
</>
) : (
t(v?.meta?.title || '')
)}
</ElBreadcrumbItem>
)
})
}
面包屑的关键特性:
- 路由同步:面包屑与当前路由同步,展示当前页面的层级关系
- 可点击导航:支持点击面包屑项导航到对应页面
- 图标支持:可展示与菜单相同的图标,提供一致的视觉体验
- 国际化支持 :通过
useI18n
hook 支持多语言显示
6.3 路由与布局的整合
项目提供了多种布局模式,路由组件被渲染在不同的布局容器中:
typescript
// 布局组件
export const Layout = () => import('@/layout/Layout.vue')
// 父级布局
export const getParentLayout = () => {
return () =>
new Promise((resolve) => {
resolve({
name: 'ParentLayout'
})
})
}
路由定义中使用布局组件:
typescript
{
path: '/dashboard',
component: Layout, // 使用主布局
redirect: '/dashboard/analysis',
children: [
{
path: 'analysis',
component: () => import('@/views/Dashboard/Analysis.vue'),
// ...
}
]
}
这种设计让系统可以灵活地处理不同层级的路由,同时保持一致的UI布局。
7. 总结
vue-element-plus-admin 项目的路由系统和权限控制展现了高度的灵活性和可扩展性,主要体现在以下方面:
7.1 系统亮点
- 三种路由模式:支持静态路由、前端动态路由和后端动态路由,适应不同场景需求
- 细粒度权限控制:实现了路由级和按钮级的权限控制
- 组件缓存机制 :通过
keep-alive
和动态缓存列表优化性能 - 多级路由处理:支持嵌套路由并提供扁平化处理
- 完整的导航体系:菜单、面包屑、标签页三位一体的导航系统
- TypeScript支持:完整的类型定义提升了代码质量和开发体验
7.2 适用场景
这种路由与权限的设计方案特别适合以下场景:
- 企业级管理系统:需要严格的权限控制和复杂的菜单结构
- 多角色应用:不同用户角色需要看到不同的功能模块
- 需要动态调整菜单的系统:菜单结构可能需要根据业务变化动态调整
- 大型前端应用:复杂的路由结构和页面间导航需求
7.3 扩展思考
在实际项目中,可以基于这套方案进行以下扩展:
- 权限数据与用户体系集成:将权限控制与实际的用户认证系统对接
- 更复杂的权限逻辑:添加基于数据范围、时间、业务状态等的权限控制
- 性能优化:针对大型应用进一步优化路由加载和组件缓存策略
- 微前端集成:将路由系统扩展为支持微前端架构的导航系统
vue-element-plus-admin 项目的路由与权限控制系统提供了一个很好的基础框架,可以根据具体业务需求进行定制和扩展,满足各种复杂场景的需求。