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 })不懂得可以参考这篇

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue菜单权限设计和实现主要包括以下几个方面: 1. 菜单数据结构设计:首先,我们需要设计一个合适的菜单数据结构,一般可以使用树形结构来表示菜单的层级关系。每个菜单项包括菜单名称、路由路径、图标、是否显示等属性。 2. 权限控制设计:在用户登录成功后,后端会返回该用户所拥有的菜单权限列表。前端可以通过保存用户的菜单权限,对用户进行菜单权限的控制。一种常用的做法是在路由守卫中判断用户是否有访问该路由的权限,并根据权限来动态渲染菜单。 3. 菜单渲染和动态展示:根据用户的菜单权限列表,前端通过递归遍历菜单数据结构,来渲染用户可见的菜单项。通过在菜单组件中动态绑定数据,可以实现菜单的展开和收起、高亮当前路由等功能。 4. 菜单操作和权限判断:除了菜单的展示,还需要考虑菜单的操作权限判断。例如,某个菜单项只有管理员才有权限访问,可以根据用户的角色或权限列表来判断该菜单项是否应该显示或可操作。 5. 菜单数据的动态更新:在某些场景下,菜单的数据可能会有动态更新。比如,管理员新增了一个菜单项,对应的路由也发生了变化。这时候,前端需要通过调用后端接口来更新用户的菜单权限列表,并且重新渲染菜单。 综上所述,Vue菜单权限设计和实现需要从菜单数据结构设计、权限控制、菜单渲染和动态展示、菜单操作和权限判断、菜单数据的动态更新等方面进行考虑和实现。通过合理的设计和实现,可以确保系统具备良好的菜单权限管理功能,提高用户体验和系统安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值