Skip to content

Vue 动态权限路由

这里的动态权限路由指的是:通过后端动态获取菜单路由(在权限系统中很常见,比如通过用户权限加载不同的菜单)

在阅读几个大型项目的源码后,步骤总结如下:

text
用户登录
 └─ router.beforeEach()
      └─ 是否已加载路由?
           ├─ 没有 → 调接口获取菜单 → 动态生成路由 → addRoute()
           └─ 已有 → 放行 next()

关键代码示例:

  1. 菜单和加载路由状态
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 }
})
  1. 前置守卫
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
})

如有转载请标注本站地址