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 就需要加载完毕,无法使用异步的方式从服务器 ...
随机推荐
- Codeforces Round #592 (Div. 2)
A. Pens and Pencils 题目链接:https://codeforces.com/contest/1244/problem/A 题意: 给定五个数 a , b , c , d , k 求 ...
- Tomcat系列(一)- 整体架构
整体架构 我们想要了解一个框架,首先要了解它是干什么的,Tomcat我们都知道,是用于处理连接过来的Socket请求的.那么Tomcat就会有两个功能: 对外处理连接,将收到的字节流转化为自己想要的R ...
- bsoj5988 [Achen模拟赛]期望 题解
bsoj5988 Description [题目背景] NOI2018 已经过去了许久,2019 届的 BSOIer 们退役的退役,颓废的颓废,计数能力大不如前.曾经的数数之王 xxyj 坦言:&qu ...
- 终极CURD-4-java8新特性
目录 1 概述 2 lambda表达式 2.1 lambda重要知识点总结 2.2 java内置函数接口 2.3 方法引用 2.4 构造器引用 2.5 数组引用 2.6 lambda表达式的陷阱 3 ...
- 【CV现状-3.0】"目标"是什么
#磨染的初心--计算机视觉的现状 [这一系列文章是关于计算机视觉的反思,希望能引起一些人的共鸣.可以随意传播,随意喷.所涉及的内容过多,将按如下内容划分章节.已经完成的会逐渐加上链接.] 缘起 三维感 ...
- iOS-关于一些取整方式
1. 直接转化 float k = 1.6; int a = (int)k; NSLog(@"a = %d",a); 输出结果是1,(int) 是强制类型转化,直接丢弃浮点数的小数 ...
- Spring Boot 设置项目名后静态文件相对路径问题
出现问题的原因 server.servlet.context-path=testDemospring.mvc.static-path-pattern=/static/**定义项目名和静态资源路径后发现 ...
- gdisk转fdisk
分区测试的时候发现之前用gdisk分区之后,就无法用fdisk进行分区了,哪怕格式化了也不行,通过fdisk 查看硬盘,发现硬盘都变成了GPT分区,无法通过fdisk进行分区操作,所以要通过parte ...
- Linux重器之 Vim 实用命令
Vim 常用的命令 光标定位; hjkl 上下左右移动 0 $ 跳到行首或行尾 gg shift+G 跳到整个文件的开头行或者结尾行 1G ,2G,3G........NG ,跳到第1.2.3 ...
- SpringBBoot整合MyBatis
一.目录展示 二.导入依赖 三.配置文件application.yml 四.Student实体类 package com.zn.entity; public class Student { priva ...