Vue 动态权限路由
这里的动态权限路由指的是:通过后端动态获取菜单路由(在权限系统中很常见,比如通过用户权限加载不同的菜单)
在阅读几个大型项目的源码后,步骤总结如下:
text
用户登录
└─ router.beforeEach()
└─ 是否已加载路由?
├─ 没有 → 调接口获取菜单 → 动态生成路由 → addRoute()
└─ 已有 → 放行 next()关键代码示例:
- 菜单和加载路由状态
ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import router from '@/router'
// 模拟后端返回菜单数据
const mockMenuData = [
{
path: '/dashboard',
name: 'Dashboard',
component: 'views/dashboard/index.vue',
meta: { title: '首页', icon: 'Home' }
},
{
path: '/user',
name: 'User',
component: 'views/user/index.vue',
meta: { title: '用户管理', icon: 'User' }
}
]
export const usePermissionStore = defineStore('permission', () => {
const isLoaded = ref(false)
const menus = ref<any[]>([])
// 模拟接口请求菜单数据
async function fetchMenus() {
return new Promise((resolve) => {
setTimeout(() => resolve(mockMenuData), 300)
})
}
// 将后端菜单转换为可用路由
function transformRoutes(menuList: any[]) {
return menuList.map((item) => {
const route: any = {
path: item.path,
name: item.name,
meta: item.meta,
component: () => import(`@/${item.component}`)
}
return route
})
}
// 加载动态路由
async function loadAsyncRoutes() {
if (isLoaded.value) return
const data = await fetchMenus()
menus.value = data as any[]
const asyncRoutes = transformRoutes(menus.value)
asyncRoutes.forEach((route) => router.addRoute(route))
isLoaded.value = true
}
return { isLoaded, menus, loadAsyncRoutes }
})- 前置守卫
ts
router.beforeEach(async (to) => {
const userStore = useUserStore()
const permissionStore = usePermissionStore()
// 未登录跳登录页
if (!userStore.isLogin && to.path !== '/login') {
return '/login'
}
// 已登录但未加载动态路由 → 调接口、添加路由
if (userStore.isLogin && !permissionStore.isLoaded) {
await permissionStore.loadAsyncRoutes()
return { ...to, replace: true } // 重新进入目标路由,确保加载完成
}
// 否则直接放行
return true
})