VUE动态展示左侧菜单

在我们实际项目开发中经常会有这样的需求,不同的用户登录系统展示不同的菜单权限,

1.效果图

管理员登录系统
在这里插入图片描述
普通用户登录系统
普通用户的权限比管理员的权限小,所有没有展示系统管理、系统日志二个菜单
在这里插入图片描述

2.实现代码

1.后台返回的数据结构

在这里插入图片描述
2.前面项目模板
https://panjiachen.github.io/vue-element-admin-site/zh/guide/
1.这里按需求下载模板
在这里插入图片描述

2.下载好项目解压完成用编辑器打开项目

3.首先封装后台返回的数据到vuex状态管理中

1.在 src\store\modules 目录下新建一个文件menu.js

后台请求接口,和cookie自行百度封装这里就不贴代码,

menu.js完整代码

import {getUserAuthority} from '@/api/user'
import {PcCookie,Key} from '@/utils/cookie'

// 定义状态
const state = {
    // 初始加载状态
    init: false,
    // 菜单数据
    menuList: [],
    // 按钮数据
    buttonList: []
}

// 改变状态
const mutations = {
    SET_SYSTEM_MENU: (state,data) =>{
        state.init = true
        state.menuList = data.userMenuList
        state.buttonList = data.userButtonList
    }
}

// 定义行为
const actions = {
    GetUserMenu({commit}){
        return new Promise((resolve,reject) =>{
            // 获取用户Id
            const userId = PcCookie.get(Key.userInfoKey) ? JSON.parse(PcCookie.get(Key.userInfoKey)).id : null
            // 发送请求
            if(userId){
                getUserAuthority({userId:userId}).then(res =>{
                    // 获取到数据,将菜单和按钮保存到vuex状态管理中
                    commit('SET_SYSTEM_MENU',res.data)
                    // 正常钩子
                    resolve()
                }).catch(error=>{
                    // 异常钩子
                    reject(error)
                })
            }
        })
    }
}

export default {
    namespaced: true,
    state,
    mutations,
    actions
}

2.写完menu.js代码把定义的状态添加到getters.js文件中
在这里插入图片描述
3.然后再permission.js触发定义的状态
在这里插入图片描述
4.动态展示左侧菜单

1.找到左侧菜单栏的代码(src\layout\components\Sidebar\index.vue)

默认左侧菜单是从路由表获取的,现在我们不用默认的路由表数据,而是从后台返回的数据中获取路由信息,这边需要自己获取后台返回的数据保存到vuex状态管理中,然后修改对应代码,
第一从vuex状态管理中获取菜单数据,
第二传递给子组件,
第三把默认的从路由表获取数据的代码注释
具体的属性名看后台返回的名字

在这里插入图片描述
2 这边他引用了一个子组件 SidebarItem我们找到子组件修改就可以了
在这里插入图片描述
3.子组件完整代码

<template>
  <div>
    <!-- 没有子菜单只有一级菜单 -->
    <template v-if="!item.children || item.children.length === 0">
      <app-link :to="item.path">
        <el-menu-item :index="item.path" :class="{'submenu-title-noDropdown':!isNest}">
          <item :icon="item.icon" :title="item.menuName" />
        </el-menu-item>
      </app-link>
    </template>

    <el-submenu v-else ref="subMenu" :index="item.menuId" popper-append-to-body>
      <template slot="title">
        <item :icon="item.icon" :title="item.menuName" />
      </template>
      <sidebar-item
        v-for="child in item.children"
        :key="child.menuId"
        :is-nest="true"
        :item="child"
        class="nest-menu"
      />
    </el-submenu>
  </div>
</template>

<script>
import path from 'path'
import { isExternal } from '@/utils/validate'
import Item from './Item'
import AppLink from './Link'
import FixiOSBug from './FixiOSBug'

export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
  mixins: [FixiOSBug],
  props: {
    // route object
    item: {
      type: Object,
      required: true
    },
    isNest: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String,
      default: ''
    }
  },
  data() {
    // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
    // TODO: refactor with render function
    this.onlyOneChild = null
    return {}
  },
  methods: {
    hasOneShowingChild(children = [], parent) {
      const showingChildren = children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          this.onlyOneChild = item
          return true
        }
      })

      // When there is only one child router, the child router is displayed by default
      if (showingChildren.length === 1) {
        return true
      }

      // Show parent if there are no child router to display
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
        return true
      }

      return false
    },
    resolvePath(routePath) {
      if (isExternal(routePath)) {
        return routePath
      }
      if (isExternal(this.basePath)) {
        return this.basePath
      }
      return path.resolve(this.basePath, routePath)
    }
  }
}
</script>

4.注意后台返回的数据中的路由地址要跟路由表的数据一致,不然点击菜单会跳转到404页面

路由表的数据如下
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐