Vue-element-admin实现菜单根据用户权限动态加载
之前有一些网友对我那个IT部门信息管理系统(http://caijt.com/it)的前端感兴趣,我已经开源到github(https://github.com/Caijt/itsys-ui)
上面有两个分支,master是对应php后端的,itsys-net是对应asp.net core后端的。

这里我简单介绍下我这个系统前端代码,当时我几乎完全参考vue-element-admin的,不过没用它的代码,但写法几乎都参考了他的教程,不过有一点不同的是,我的路由跟菜单是动态生成的,是后台根据当前登录的用户,查询用户的角色,再查询角色所具有的菜单列表,返回到前端,然后在前端生成Routers树数据,再用router.addRouters方法挂载到router上,当然vue-element-admin的作者也有考虑到这个问题,看下图。

那我来介绍下我的系统是怎么实现这种动态权限的需求的,当然我的代码不完全跟vue-element-admin一样,只是提供一种思路。
先介绍下我数据表(sys_menu)的结构,如下图所示,很明显,我的数据表(sys_menu)是一个树型结构,主要的字段有id,title(决定你前端菜单的标题),path(很重要,前端会根据这个值去寻找views下面的vue文件,所以前端创建的文件夹名称必须跟这个值一致),parent_id(父级菜单id),order(菜单的排序顺序),还有一个parent_ids字段, 这个只是我在其它查询中的一个辅助字段,在这里没什么作用。

后端获取菜单数据,以下sql不涉及角色菜单的判断
select id,title,path,parent_id from sys_menu order by `order`
前端得到这样的对象数组,如下图所示

let menuList = res.data.menuList //这是后端的菜单数据 let menuRouters = [] //定义一个空数组,这个是用来装真正路由数据的 //下面就要根据后端的菜单数据组装树型路由数据
//先取出根节点,没有父id的就是根节点
menuList.forEach((m, i) => {
if (m.parent_id == null) {
m.fullPath = '/' + m.path
let module = {
path: '/' + m.path,
component: layout,
meta: { id: m.id, title: m.title, fullPath: '/' + m.path },
children: [
{
path: '',
component:() => import('@/views/' + m.path + '/index')
meta: {
menuHide: true,
title: m.title
}
}
]
}
menuRouters.push(module)
}
})
//定义一个递归方法
function convertTree(routers) {
routers.forEach(r => {
menuList.forEach((m, i) => {
if (m.parent_id && m.parent_id == r.meta.id) {
if (!r.children) r.children = []
m.fullPath = r.meta.fullPath + '/' + m.path
let menu = {
path: m.path,
component: () => import('@/views'+r.meta.fullPath+'/'+m.path),
meta: { id: m.id, title: m.title, fullPath: r.meta.fullPath + '/' + m.path }
}
r.children.push(menu)
}
})
if (r.children) convertTree(r.children)
})
}
convertTree(menuRouters) //用递归填充
router.addRoutes(menuRouters) //挂载到router
路由挂载好后,我同时把menuRouters赋值给vuex($store.state.user.routers),方便我在menu组件中调用
还有我的系统跟vue-element-admin菜单显示也有所不同,我是按模块显示菜单的,如下图所示,vue-element-admin是菜单统一显示左边栏上

那么处理起来很容易,在我的系统里,根节点就是模块,根节点的子菜单,就是该模块下的菜单列表
顶部模块跟左侧菜单组件都是用element-ui的NavMenu组件,只是模块的是用一个horizontal水平的,菜单是vertical垂直的
//以下是顶部模块菜单的代码
<el-menu
class="_layout-header"
router
mode="horizontal"
:default-active="modulePath"
background-color="#304156"
text-color="#fff"
active-text-color="#409EFF"
style="border:none"
ref="elHeader"
>
<el-menu-item
v-for="m in $store.state.user.routers.slice(0,maxShowHeaderMenu)"
:index="m.path"
:key="m.meta.id"
>{{ m.meta.title }}</el-menu-item>
<el-submenu index="/more" v-if="$store.state.user.routers.length>maxShowHeaderMenu">
<template slot="title">更多</template>
<el-menu-item
v-for="m in $store.state.user.routers.slice(maxShowHeaderMenu)"
:index="m.path"
:key="m.meta.id"
>{{ m.meta.title }}</el-menu-item>
</el-submenu>
<el-submenu index="/my" style="float:right;">
<template slot="title">{{$store.state.user.name}}</template>
<el-menu-item index @click="logout">注销</el-menu-item>
</el-submenu>
</el-menu> //maxShowHeaderMenu 值是根据当前页面大小跟模块数量计算出最多可以显示多少个模块菜单,其余模块菜单会放进一个更多的折叠按钮下,是为了防止模块太多,导致顶部模块菜单超出,导致样式变形 //this.maxShowHeaderMenu = Math.floor(document.body.clentWidth / 100) -3;
以下是左侧菜单的组件,可实现哪个模块就显示哪些菜单
//左侧菜单
<el-scrollbar class="_scroll">
<el-menu
class="_layout-nav"
:default-active="$route.path"
:default-openeds="openedMenus"
router
ref="menu"
style="border:none"
@select="select"
>
<el-menu-tree
v-for="menu in $store.state.user.routers"
v-show="menu.path==modulePath"
:menus="menu.children||[]"
:key="menu.path"
></el-menu-tree>
</el-menu>
</el-scrollbar>
//上面代码里封装的一个el-menu-tree组件
<template>
<div>
<template v-for="m in filterMenus">
<el-menu-item
v-if="typeof(m.children)=='undefined' || m.children.length==0"
:key="m.meta.id"
:index="m.meta.fullPath"
>{{m.meta.title}}</el-menu-item>
<el-submenu v-else :index="m.meta.fullPath" :key="m.meta.id">
<template slot="title">{{m.meta.title}}</template>
<el-menu-tree :menus="m.children"></el-menu-tree>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: "elMenuTree",
props: {
menus: {
type: Array
}
},
computed: {
filterMenus() {
return this.menus.filter(item => !item.meta.menuHide);
}
}
};
</script>
对了,还有一个面包屑

这个很容易,主要是根据$route.matched数组
<el-breadcrumb separator="/" style="margin-bottom: 20px">
<el-breadcrumb-item
v-for="m in breadItems"
:key="m.meta.id"
:to="m.path"
@click.native="itemClick"
>{{m.meta.title}}</el-breadcrumb-item>
</el-breadcrumb>
//breadItems = this.$route.matched.filter(item=>!item.meta.menuHide);
Vue-element-admin实现菜单根据用户权限动态加载的更多相关文章
- vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单
一. 前言 本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动 ...
- jstree无限级菜单ajax按需动态加载子节点
业余时间研究了一下jstree,更新非常快已经是3.0了,首先看一下效果截图: 1.页面引入样式和脚本(注意路径根据实际情况) <link href="~/Scripts/vakata ...
- SpringBoot集成Shiro 实现动态加载权限
一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...
- Asp.Net Core 项目实战之权限管理系统(8) 功能菜单的动态加载
0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...
- Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单
动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...
- Vue + Element UI 实现权限管理系统(动态加载菜单)
动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...
- SpringSecurity动态加载用户角色权限实现登录及鉴权
很多人觉得Spring Security实现登录验证很难,我最开始学习的时候也这样觉得.因为我好久都没看懂我该怎么样将自己写的用于接收用户名密码的Controller与Spring Security结 ...
- C#自定义控件、用户控件、动态加载菜单按钮
一.效果图,动态加载5个菜单按钮: 二.实现方法 1.创建用户控件 2.在用户控件拖入toolStrip 3.进入用户控件的Lood事件,这里自动添加5个选 ToolStripMenuItem,后期 ...
- vue路由动态加载
注意:是动态加载不是动态路由 解决的问题: 动态配置菜单栏的路由参数--实现菜单级的权限控制 问题成因: 在vue实例化的时候vuex.vue-router 就需要加载完毕,无法使用异步的方式从服务器 ...
随机推荐
- re常用模块
re模块:从字符串里面找到特定的字符串 re的基本语法(匹配规则) import re s = '王大炮打炮被大炮打死了 王大炮打炮被大炮打死了' ^:开头 print(re.findall('^王大 ...
- [ASP.NET Core 3框架揭秘] 跨平台开发体验: Linux
如果想体验Linux环境下开发.NET Core应用,我们有多种选择.一种就是在一台物理机上安装原生的Linux,我们可以根据自身的喜好选择某种Linux Distribution,目前来说像RHEL ...
- 在Chrome 中使用Vimium
原文连接:https://blog.csdn.net/wuxianjiezh/article/details/91848604 Vimium:像在 Vim 中一样使用 Chrome 安装 使用方法 在 ...
- SpringCloud-使用熔断器仪表盘监控熔断
场景 SpringCloud-使用熔断器防止服务雪崩-Ribbon和Feign方式(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/ ...
- CentOS 服务器版安装教程(超级详细图解)
使用安装说明:http://www.jb51.net/os/85895.html
- .NET Core 发布(dotnet publish)
目录 一.需求 二.方法 三.参考 一.需求 使用.net core 3.0建的项目,一般情况下,每次想发布都要打开vs,然后点击发布,选择配置: 如果想用cmd命令行发布,应该怎么写呢? 二.方法 ...
- PHP最新面试题2019
1.字符串"0"在PHP和js中转换为布尔值是false还是true php:false; php 弱语言 '0'和0一样: js:true:字符串除了空字符串('')其他都是t ...
- C# List与Dictionary相互转换与高效查找
TestModel类定义: public class TestModel{ public int Id { get; set; } public string Name { get; se ...
- BlockStack常见词语
Browser: 用户用来浏览并使用基于 blockstack 网络开发的 app. CLI: Cli 工具用来管理个人的 blockstack id. blockstack.js (and othe ...
- react学习之js-xlsx导入和导出excel表格
前记:最近真的挺忙的,一件事接着一件,都忘了我的React项目,尽管这是一个没写概率没写离散的夜晚,我决定还是先做做我的React 好了,进入正题 项目需求,需要导入和导出表单,发现前端已经强大到无所 ...