新手上路。项目需求比较简单,不要求控制到按钮,只需控制到页面,有权限显示,没有权限不显示该页面。
网上很多方法,看的好几脸懵逼,不确定用什么方法。直到搜到以下demo,有了demo赶脚拥有了上帝视角,在此基础上改成自己适用的。
1.基于Vue实现后台系统权限控制这是个比较华丽的demo,但是对于我来说页面很多,反而很难提取到某个功能关键代码。
2.Vue动态菜单(路由)的实现方案(beforeEach+addRoutes+elementUI)这个简单易懂。
看代码还是容易的,就不贴我的实现了,记录下主要步骤:
1.最重要的就是本地路由表了
meta下的roles属性控制了是否在菜单中显示该页面,这个demo中用的是用户角色,我的项目中没有分配角色,后端返回给我有权限的菜单list,因此我的roles属性直接填写菜单名称即可匹配。
跳转,显示很多都读取这个文件内容。根据自己情况增删属性
//代码位置:router/index.js
{
path: '',
component: layout, //整体页面的布局(包含左侧菜单跟主内容区域)
children: [{
path: 'main',
component: main,
meta: {
title: '首页', //菜单名称
roles: ['user', 'admin'], //当前菜单哪些角色可以看到 (我的这里改为菜单名称)
icon: 'el-icon-info' //菜单左侧的icon图标
}
}]
}
2.向上面roles中塞数据
用到了localStorage,我理解为全局变量,我的这篇博客 1.2有写
登录后,拿到权限存到变量中
let getUserRole = this.formModel.user === 'admin' ? 'admin' : 'user'
localStorage.setItem('userRole', getUserRole)
//代码位置:src/permission.js
// 取到用户的角色
let GetRole = localStorage.getItem("userRole")
//。。。demo中有,去掉一些逻辑,只展示如何添加到roles
// 4.将生成好的路由addRoutes
router.addRoutes(fixedRouter.concat(getRoutes))
这里roles已经有值了,这两步是最重要的,可以实现过滤。剩下就是渲染菜单的组件sideMeuns.vue重新生成左侧菜单。
菜单中显示也是通过读取路由数据,router/index.js中要调成自己合适的结构。
demo中我修改的地方:
1.左侧菜单是通过router-link组件跳转的,加上背景色,会有紫色下划线,感觉很丑。在父组件menu中加上router也可跳转。
<el-aside class="slider_container">
<el-menu
background-color="#304156"
router
>
<!-- 菜单组件 -->
<side-Meuns :routes="getMyRoutes"></side-Meuns>
</el-menu>
2.如果菜单下只有一个子菜单时,就不显示它的父菜单了。不符合我的业务需求
一级菜单也需要显示主菜单,添加以下代码。
<!-- 一级菜单的情况 -->
<template v-if="item.children&&item.children.length<=1">
<el-submenu :index="item.path">
<template slot="title">
<!-- 设置icon -->
<i v-if="item.meta" :class="item.meta.icon"></i>
<!-- 菜单名称 -->
{{ item.title }}
</template>
3.增加面包屑导航栏
增加导航栏子组件breadcrumbNav.vue:
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group>
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path" v-if="item.meta.title">
<span v-if='item.redirect==="noredirect"||index==levelList.length-1' class="no-redirect">{{item.meta.title}}</span>
<router-link v-else :to="item.redirect||item.path">{{item.meta.title}}</router-link>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
export default {
name: "idnex",
data(){
return {
levelList:null
}
},
created() {
this.getBreadcrumb()
},
watch:{
$route(){
this.getBreadcrumb()
}
},
methods:{
getBreadcrumb(){
let matched=this.$route.matched.filter(item=>item.name)//$route.matched 将会是一个包含从上到下的所有对象 (副本)。
const first=matched[0]
if(first && first.name !=='dashboard'){//$route.name当前路由名称 ;$route.redirectedFrom重定向来源的路由的名字
matched=[{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
}
this.levelList=matched
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 10px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>
在父组件中添加
<!-- 面包屑导航 -->
<breadcrumbNav :currentPath="breads"></breadcrumbNav>
<script>
import breadcrumbNav from "../common/breadcrumbNav"; //面包屑路径
</script>
export default {
components: {
sideMeuns,
breadcrumbNav
},
}
仅记录,如有错误欢迎指正。
有更优雅的方案,期待分享交流。