vue3菜单权限管理实现

前提

你的菜单是根据路由动态生成的,具体可以参考这篇博客对el-menu组件进行递归封装(根据路由配置动态生成)

描述

首先将路由分为常量路由constantRoute(所有用户都有的路由)和异步路由asyncRoute(需要动态加载的前端路由)
每次进入系统时根据不同的用户向后端发送请求获取该用户的路由权限信息,一般是个数组。

所使用的API

1.动态添加路由api

router.addRoute(parentName: string, route: RouteConfig): () => void

实现的例子

路由配置信息(大概扫一眼就行,就是v-router的配置)

export const constantRoute = [
  {
    path: '/login',
    component: () => import('@/views/login/index.vue'),
    name: 'login',
    meta: {
      title: '登录',
      hidden: true,
    },
  },
  {
    path: '/',
    component: () => import('@/views/layout/index.vue'),
    name: 'layout',
    meta: {
      title: '',
      hidden: false,
      icon: '',
    },
    redirect: '/home',
    children: [
      {
        path: '/home',
        component: () => import('@/views/home/index.vue'),
        name: 'home',
        meta: {
          title: '首页',
          hidden: false,
          icon: 'HomeFilled',
        },
      },
    ],
  },
  {
    path: '/screen',
    component: () => import('@/views/screen/index.vue'),
    name: 'Screen',
    meta: {
      title: '数据大屏',
      hidden: false,
      icon: 'DataBoard',
    },
  },
  {
    path: '/404',
    component: () => import('@/views/404/index.vue'),
    name: '404',
    meta: {
      title: 'Not Found',
      hidden: true,
    },
  },
  {
    path: '/:pathMatch(.*)*',
    redirect: '404',
    name: 'Any',
    meta: {
      title: 'Not Found',
      hidden: true,
    },
  },
]

export const asyncRoute = [
  {
    path: '/acl',
    component: () => import('@/views/layout/index.vue'),
    name: 'Acl',
    meta: {
      title: '权限管理',
      hidden: false,
      icon: 'Lock',
    },
    redirect: '/acl/user',
    children: [
      {
        path: '/acl/user',
        component: () => import('@/views/acl/user/index.vue'),
        name: 'User',
        meta: {
          title: '用户管理',
          hidden: false,
          icon: 'User',
        },
      },
      {
        path: '/acl/role',
        component: () => import('@/views/acl/role/index.vue'),
        name: 'Role',
        meta: {
          title: '角色管理',
          hidden: false,
          icon: 'Avatar',
        },
      },
      {
        path: '/acl/permission',
        component: () => import('@/views/acl/permission/index.vue'),
        name: 'Permission',
        meta: {
          title: '菜单管理',
          hidden: false,
          icon: 'List',
        },
      },
    ],
  },
  {
    path: '/product',
    component: () => import('@/views/layout/index.vue'),
    name: 'Product',
    meta: {
      title: '商品管理',
      hidden: false,
      icon: 'Goods',
    },
    redirect: '/product/trademark',
    children: [
      {
        path: '/product/trademark',
        component: () => import('@/views/product/trademark/index.vue'),
        name: 'Trademark',
        meta: {
          title: '品牌管理',
          icon: 'ShoppingCart',
          hidden: false,
        },
      },
      {
        path: '/product/attr',
        component: () => import('@/views/product/attr/index.vue'),
        name: 'Attr',
        meta: {
          title: '属性管理',
          icon: 'Management',
          hidden: false,
        },
      },
      {
        path: '/product/spu',
        component: () => import('@/views/product/spu/index.vue'),
        name: 'Spu',
        meta: {
          title: 'Spu',
          icon: 'SetUp',
          hidden: false,
        },
      },
      {
        path: '/product/sku',
        component: () => import('@/views/product/sku/index.vue'),
        name: 'Sku',
        meta: {
          title: 'Sku',
          icon: 'ScaleToOriginal',
          hidden: false,
        },
      },
    ],
  },
]

// 计算异步路由信息
function generateRoutes(asyncRoutes: any, filterArr: string[]) {
  return asyncRoutes.filter((item: any) => {
    if (filterArr.includes(item.name)) {
      if (item.children && item.children.length > 0) {
        item.children = generateRoutes(item.children, filterArr)
      }
      return true
    }
  })
}
// filterArr 权限信息
const filterArr = ['Acl', 'User', 'Role', 'Product', 'Trademark']
const asyncRoutes = generateRoutes(
  // 一定要使用深拷贝 用lodash的cloneDeep,不要用JSON的那个
  cloneDeep(asyncRoute),
  filterArr,
)
// this.routes主要是侧边导航栏要的信息 可有可无
this.routes = [...constantRoute, ...asyncRoutes,...anyRoute];
// 动态注册路由
[...asyncRoutes,...anyRoute].forEach((item:any) => {
  router.addRoute(item)
});

注意:如果出现Vue 路由定义警告Component “default“ in record with path “/“ is a Promise这个问题可以尝试在路由前置守卫中加入判断使用next({ ...to })不懂得可以参考这篇

你可能感兴趣的:(vue.js,前端,javascript)