vue router 根据路由区分用户权限并生成动态侧边栏
背景往往在管理后台系统中,vue-router 要做更多的事情挂载组件到页面根据不同的用户角色,如:超级管理员,审计用户,普通用户等来做权限管理生成复杂的侧边栏那么,如何使用一套定义好的 router 来做到以上三个需求呢?分析首先,我们来细致的分析一下这三个需求有哪些具体需要挂载组件到页面中想必不用多说了,vue-router 本来就是做这个的区分不同用户角色用户角色是用户登录后后台返回的,比如
·
背景
往往在管理后台系统中,vue-router 要做更多的事情
- 挂载组件到页面
- 根据不同的用户角色,如:超级管理员,审计用户,普通用户等来做权限管理
- 生成复杂的侧边栏
那么,如何使用一套定义好的 router 来做到以上三个需求呢?
分析
首先,我们来细致的分析一下这三个需求有哪些具体需要
挂载组件到页面中
想必不用多说了,vue-router 本来就是做这个的
区分不同用户角色
用户角色是用户登录后后台返回的,比如这个字段是user_role
,那么,
- 首先,我们可以把这个字段首先存储在 vuex 中,这样可以全局访问
- 其次,在 vue-router 的每一个路由对象中插入一个字段,比如叫
permission
来记录当前这个路由能够被谁访问 - 根据
user_role
和permission
来筛选所有的路由,筛选后的结果,就是当前用户能够访问的路由
生成复杂的侧边栏
侧边栏是管理后台都有的功能,这里参考 vue-element-admin 的实现。
本质上就是遍历 router,利用 elementui 的 el-menu 组件来生成就可以了。
实现
router,js 中实现了用户权限的区分,并抛出结果用于生成侧边栏
sidebar 则是生成侧边栏的逻辑
// router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import layout from '@/layout'
Vue.use(VueRouter)
// hidden: 是否显示在侧边栏
// name: 侧边栏对应的文字内容,当name不存在,则children中的路由为一级路由,否则为二级路由,侧边栏最多显示到二级路由
// iconName:侧边栏的 icon 图标
// permission:可以访问辞路由的用户列表
const router1 = [
{
path: '/',
redirect: '/homepage',
hidden: true,
meta: { permission: [1, 2, 3] }
},
{
path: '/homepage',
meta: { permission: [1, 2, 3] },
redirect: '/homepage/dashboard',
component: layout,
children: [
{
path: 'dashboard',
name: '安全状态监控',
meta: { iconName: 'icon-erji-loudongsaomiaoguanli', permission: [1, 2, 3] },
component: () => import('../views/dashboard/index.vue'),
},
]
},
{
path: '/assetManagement',
name: '资产管理',
meta: { iconName: 'icon-erji-loudongsaomiaoguanli', permission: [1, 2, 3] },
redirect: '/assetManagement/assetList',
component: layout,
children: [
{
path: 'assetList',
name: '资产列表',
meta: { permission: [1, 2, 3] },
component: () => import('../views/assetManagement/assetList.vue'),
},
{
path: 'assetDetail',
name: '资产详情',
meta: { permission: [1, 2, 3] },
component: () => import('../views/assetManagement/assetList.vue'),
},
]
},
{ path: '/login', component: () => import('@/views/login.vue'), hidden: true,
meta: { permission: [1, 2, 3] }, },
{ path: '*', redirect: '/', hidden: true, meta: { permission: [1, 2, 3] }, }
]
const roleType = store.getters.user_role
function permissionRouter(router=router1) {
return router.filter(item => {
if(item.children)
item.children = permissionRouter(item.children)
return item.meta.permission.includes(roleType)
})
}
export const routes = permissionRouter() // 根据这个路由去生成侧边栏
export default new VueRouter({
routes
})
router 写好以后就可以准备侧边栏了,侧边栏逻辑复杂一点,所以我也是拆成了三个文件
sidebar
├── index.vue
├── item.vue
├── sidebarItem.vue
// index.vue
<template>
<div class="sidebar-container">
<el-menu :unique-opened="true"
:collapse-transition="false"
background-color="rgba(0,0,0,0)"
:default-active="activeMenu">
<sidebar-item v-for="(item, index) in routes"
:key="index"
:item="item" />
</el-menu>
</div>
</template>
<script>
import { routes } from '@/router'
import SidebarItem from './sidebarItem.vue'
export default {
components: {
SidebarItem
},
data() {
return {
routes
}
},
computed: {
activeMenu() {
return this.$route.path
}
}
}
</script>
// item.vue
<template>
<el-menu-item :index="compilePath(child.path)"
@click="clickEvent(child)"
v-if="!child.hidden">
<i v-if="child.meta"
class="iconfont"
:class="child.meta.iconName"></i>
<span slot="title">{{child.name}}</span>
</el-menu-item>
</template>
<script>
import path from 'path'
export default {
props: {
child: {
type: Object
},
basePath:{
type: String
}
},
methods: {
compilePath(childpath) {
return path.resolve(this.basePath, childpath)
},
clickEvent(child) {
const path = this.compilePath(child.path)
this.$router.push(path)
}
}
}
</script>
// sidebarItem.vue
<template>
<el-submenu v-if="(item.children && hasName(item)) && !item.hidden"
:index="item.path">
<template slot="title">
<i v-if="item.meta"
class="iconfont"
:class="item.meta.iconName"></i>
<span slot="title">{{item.name}}</span>
</template>
<menu-item v-for="child in item.children"
:key="compilePath(item.path,child.path)"
:child="child"
:basePath="item.path" />
</el-submenu>
<menu-item :child="item.children[0]"
v-else-if="item.children && !item.hidden"
:basePath="item.path" />
</template>
<script>
import path from 'path'
import MenuItem from './item.vue'
export default {
props: {
item: {
type: Object
}
},
components: {
MenuItem
},
methods: {
compilePath(itempath, childpath) {
return path.resolve(itempath, childpath)
},
hasName(item){
return item.name? true: false
}
}
}
</script>
这样,我们的整个需求就完成了,然后将 sidebar 组件正常引入,加入自己的样式,就可以了。下面是引入
<template>
<div class="flex-box app-content">
<side-bar class="sidebar" />
</div>
</template>
<script lang="es6">
import sideBar from './sidebar/index.vue'
export default {
components: {sideBar},
data(){
return {
Tony: 'Tony'
}
}
}
</script>
看下结果
最后的最后,代码未经测试,有任何问题请私信或评论,谢谢。
更多推荐
已为社区贡献5条内容
所有评论(0)