之前有一些网友对我那个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实现菜单根据用户权限动态加载的更多相关文章

  1. vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单

    一. 前言 本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动 ...

  2. jstree无限级菜单ajax按需动态加载子节点

    业余时间研究了一下jstree,更新非常快已经是3.0了,首先看一下效果截图: 1.页面引入样式和脚本(注意路径根据实际情况) <link href="~/Scripts/vakata ...

  3. SpringBoot集成Shiro 实现动态加载权限

    一.前言 本文小编将基于 SpringBoot 集成 Shiro 实现动态uri权限,由前端vue在页面配置uri,Java后端动态刷新权限,不用重启项目,以及在页面分配给用户 角色 . 按钮 .ur ...

  4. Asp.Net Core 项目实战之权限管理系统(8) 功能菜单的动态加载

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  5. Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单

    动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...

  6. Vue + Element UI 实现权限管理系统(动态加载菜单)

    动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...

  7. SpringSecurity动态加载用户角色权限实现登录及鉴权

    很多人觉得Spring Security实现登录验证很难,我最开始学习的时候也这样觉得.因为我好久都没看懂我该怎么样将自己写的用于接收用户名密码的Controller与Spring Security结 ...

  8. C#自定义控件、用户控件、动态加载菜单按钮

    一.效果图,动态加载5个菜单按钮: 二.实现方法 1.创建用户控件 2.在用户控件拖入toolStrip 3.进入用户控件的Lood事件,这里自动添加5个选  ToolStripMenuItem,后期 ...

  9. vue路由动态加载

    注意:是动态加载不是动态路由 解决的问题: 动态配置菜单栏的路由参数--实现菜单级的权限控制 问题成因: 在vue实例化的时候vuex.vue-router 就需要加载完毕,无法使用异步的方式从服务器 ...

随机推荐

  1. IIS中部署网站

    1.安装开IIS,打开IIS(Win+R -->inetmgr.exe) 2.进入IIS主界面,右键网站,选择“添加网站”. 3.在“添加网站”对话框中,添加网站名称. 4.点击应用程序池选择, ...

  2. js中正则表达式的易错点

    文章目录 1. 匹配符部分匹配规则 2. 分组匹配规则: 3. 注意^的不同用法 4. 不要忘记转义 5. 正则表达式对象中lastIndex属性 6. exec VS match 1. 匹配符部分匹 ...

  3. kuangbin专题 数论基础 part1?

    线段树专题太难了,那我来做数学吧! 但数学太难了,我......(扯 这两天想了做了查了整理了几道数学. 除了一些进阶的知识,像莫比乌斯反演,杜教筛,min25学不会我跳了,一些基础的思维还是可以记录 ...

  4. TP5中find_in_set的用法

    TP5.1.22版本 $id=4; Db::name('menu')->where('FIND_IN_SET(:id,pid_all)',['id' => $id])->update ...

  5. SAP MM ME57界面看到的供应源跟Source List主数据不一致?

    SAP MM ME57界面看到的供应源跟Source List主数据不一致? ME57,为如下的PR单据分配供应源, 发现找不到想要分配的供应源. ME03 去看Source List主数据, 黄色标 ...

  6. flutter_boot android和flutter源码阅读记录

    版本号0.1.54 看源码之前,我先去看下官方文档,对于其源码的设计说明,文中所说的原生都是指android 看完官方文档的说明,我有以下几个疑问 第一个:容器是怎么设计的? 第二个:native和f ...

  7. BIM工程信息管理系统-详细设计

    详细设计说明书 1引言 1.1编写目的 编写详细设计说明书的目的就是为程序员写出实际的程序代码提供依据.它是软件详细设计阶段所有任务和所有相关人员所需的参考资料. 1.2背景 说明: a.  软件名称 ...

  8. linux 常用Mysql脚本命令

    常用命令 无需系统Root权限 新数据库设置Root密码 visible > mysql -uroot -p visible > mysqladmin -uroot password &q ...

  9. pyecharts画图总结

    pyecharts 画图归纳 将本地文件导入到Pyecharts: test = open(filename, 'r') data = test.readlines() test.close() 如果 ...

  10. ESPCMS P8 stable version Front-end reflective xss

    Download the source code first In the directory espcms_web\espcms_load.php line 67 if (!is_file($mod ...