涉及权限的element嵌套菜单

需要用到的插件,vuex持久化插件(vuex-persistedstate),vuex,element-ui(需要用到el-menu,如果有其他的也可以使用)

适用场景:老项目新加角色路由权限需求时,初次接触权限路由菜单

不适用场景:新项目中涉及动态路由

流程:在路由配置中设置对应权限标识,和后台返回相同即可,在登录页面设置处理组装路由方式,处理好后存储在vuex中,在对应页面引入封装好的菜单组件,然后在vuex中拿到菜单列表渲染即可

1.首先在router中设置对应路由权限,提前配置好,只需要在menu中设置一个判断值

2.在登录中对路由(子路由)进行判断是否有权限渲染,全部判断完之后添加至vuex的状态中

3.在首页(包含但不限于)中进行嵌套菜单组件引入,在从vuex中取出菜单列表渲染即可

接下来是代码流程展示

1.设置对应权限标识(subMenuType)

 {
    path: '/home',
    menu: true, // 菜单路由标识字段
    component: () => import('@/views/home.vue'),
    children: [
      // 会议
      {
        path: '/schedule',
        title: '会议',
        label: '会议',
        component: () => import('@/views/schedule/schedule.vue'),
        meta: {
          title: '会议',
          icon: 'el-icon-s-custom',
          menuPermission: 'schedule'
        }
      },
      // 运维
      {
        path: '',
        title: '运维',
        label: '运维',
        component: () => import('@/views/monitor/monitor.vue'),
        meta: {
          title: '运维',
          icon: 'el-icon-s-custom',
          menuPermission: 'monitor'
        },
        children: [
          {
            path: '/log',
            title: '日志管理',
            label: '日志管理',
            component: () => import('@/views/monitor/systemSettings/LeftRightLayout.vue'),
            meta: {
              title: '日志管理',
              // subMenuType 这个字段有值时,菜单数据组装时会忽略当前路由的子路由数据。
              // 在此处,组装菜单时,“操作日志”子路由会被忽略
              subMenuType: 'logger',
              menuPermission: 'logger'
            },
            children: [
              {
                path: '/log/operation-log',
                name: '操作日志',
                component: () => import('@/views/monitor/LogManagement/OperationLog.vue'),
                meta: {
                  title: '操作日志',
                  menuPermission: 'logger',
                }
              }
            ]
          }
        ]
      },
    ]
  }

2.在登录页面进行权限路由拦截

 submitForm(formName) {
      // console.log(formName);
      this.$refs[formName].validate((valid) => {
        if (valid) {
          console.log('正则校验之后进入判断')
           this.PermissionsMenu(staticRouter.options.routes, ['monitor','logger'])
          // console.log(this.PermissionsMenu);
        } else {
          console.log('正则校验失败')
          return false
        }
      })
    },
 PermissionsMenu(staticRouter, permissions) {
     const that = this;
      const filterMenus = function (menus, accessMenu) {
        // console.log(menus,);
        menus.forEach((m) => {
          // 主菜单组装
          if (m.children && !m.meta.subMenuType) {
            // 有子路由,且subMenuType没有值,说明该子路由属于子菜单
            let subMenu = [];
            // m.children说明当前路由还有子路由,继续递归
            filterMenus(m.children, subMenu);
            // 递归后,如果子路由组装后存在值,则将子路由的值合并到当前路由的children,并将当前路由push到最终accessMenu中
            if (subMenu.length > 0) {
              let _aMenu = Object.assign({}, m);
              _aMenu.children = subMenu;
              accessMenu.push(_aMenu)
            }
          } else {
            // console.log(m,'过滤了菜单');
            // 过滤子菜单(子路由不属于头部菜单时,需要进行过滤)
            if (m.meta.subMenuType) {
              m.children && delete m.children
            }
            // 递归遍历菜单,筛选有权限的菜单
            console.log(m.meta.menuPermission);
            permissions.includes(m.meta.menuPermission) && accessMenu.push(m)
          }
        })
      };
      //以上是复用函数
      let menus = []; // 全部菜单路由
      let accessMenu = []; // 根据权限过滤后的菜单路由
      // 获取路由是菜单的部分
      console.log(staticRouter,'打印静态路由');
      staticRouter.forEach((item) => {
        if (item.menu) {
          // 菜单路由
          menus = item.menu ? menus.concat(item.children) : menus
        }
      });
      console.log('组装前--全部菜单路由', menus);
      // 根据当前用户菜单权限来组装菜单列表
      filterMenus(menus, accessMenu);
      // 保存到vuex中
      this.$store.commit('setUser', accessMenu)
      // this.$store.state.user.accessMenu=accessMenu
      this.$router.push('/home')
      console.log(this.$store);
    },

3.在对应页面引入菜单组件

<el-menu
      :default-active="activeMenu"
      class="el-menu-demo"
      mode="horizontal"
      :router="true"
    >
      <template v-for="menu in user.accessMenu">
        <el-menu-item
          class="sub-nav"
          v-if="!menu.children"
          :key="menu.title"
          :index="menu.path"
        >
          <i :class="menu.icon" v-if="menu.icon"></i>
          <span slot="title">{{menu.title }}</span>
        </el-menu-item>
        <the-submenu
          :key="menu.title"
          :subMenu="menu"
          v-else
        ></the-submenu>
      </template>
    </el-menu>
<script>
import TheLayoutSubSidebar from '@/components/TheLayoutSubSidebar/TheLayoutSubSidebar.vue'
export default {
   components: { 'theSubmenu': TheLayoutSubSidebar },
  props: {},
  data() {
    return {
      user:[],
    }
  },
  
   computed: {
    activeMenu() {
      const route = this.$route
      console.log(route);
      const { meta, path } = route
      if (meta.activeMenu) {
        return meta.activeMenu
      }
      return path
    },
  },
  mounted() {
    this.user=this.$store.state.user
  },
}
</script>

若是没有更好的菜单组件可以使用这个

<el-submenu v-on="listeners" :key="data.key" :index="data.key">
    <template slot="title">
      <i :class="data.attrs.subMenu.icon" v-if="data.attrs.subMenu.icon"></i>
      <span slot="title">{{ data.attrs.subMenu.title }}</span>
    </template>
    <template v-for="item in data.attrs.subMenu.children">
      <el-menu-item v-if="!item.children" :key="item.title" :index="item.path">
        <a-icon :type="item.icon" v-if="item.icon" />
        <span>{{ item.title }}</span>
      </el-menu-item>
      <the-submenu
        v-else
        :subMenu="item"
        :key="item.title"
      ></the-submenu>
    </template>
  </el-submenu>
import TheLayoutSubSidebar from '@/components/TheLayoutSubSidebar/TheLayoutSubSidebar.vue'
export default {
  components: { theSubmenu: TheLayoutSubSidebar },
  props: {},
  data() {
    return {}
  },
}

 一定不要忘了引入哦!

import Vue from 'vue'
import App from './App.vue'

import router from './router'
import store from './store'

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

// global css
import './assets/styles/index.scss'
Vue.use(ElementUI)

new Vue({
  router,
  store,
  el: '#app',
  render: function (h) { return h(App) }
}).$mount('#app')

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值