前言:
需求:需要根據(jù)不用的用戶匹配不同的管理權(quán)限,既:匹配不同的操作導(dǎo)航,尤其體現(xiàn)在后臺(tái)管理系統(tǒng)內(nèi),如果僅僅只是在導(dǎo)航菜單內(nèi)不予顯示,仍然是可以通過(guò)路徑直接打開頁(yè)面,因?yàn)槠渎酚尚畔⒁呀?jīng)在路由信息對(duì)象(new Router({}))函數(shù)中進(jìn)行了注冊(cè)
當(dāng)然 這里可以通過(guò)全局導(dǎo)航守衛(wèi)來(lái)區(qū)分不同的用戶,允許其進(jìn)入不同的路徑,但是這只能進(jìn)行簡(jiǎn)單的權(quán)限判斷,且前端已經(jīng)寫死,靈活性不高,不能針對(duì)每個(gè)用戶,做定制化權(quán)限區(qū)分
項(xiàng)目地址:https://github.com/cgq001/vue-admin
歡迎start
使用到的規(guī)則
1、動(dòng)態(tài)設(shè)置權(quán)限的UI展示
這里使用element-ui的Three樹形控件,數(shù)據(jù)結(jié)構(gòu)如下:
data: [{
id: 1,
label: '一級(jí) 1',
children: [{
id: 4,
label: '二級(jí) 1-1',
children: [{
id: 9,
label: '三級(jí) 1-1-1'
}, {
id: 10,
label: '三級(jí) 1-1-2'
}]
}]
}, {
id: 2,
label: '一級(jí) 2',
children: [{
id: 5,
label: '二級(jí) 2-1'
}, {
id: 6,
label: '二級(jí) 2-2'
}]
}, {
id: 3,
label: '一級(jí) 3',
children: [{
id: 7,
label: '二級(jí) 3-1'
}, {
id: 8,
label: '二級(jí) 3-2'
}]
}]
這里選擇這個(gè)樹形控件,是因?yàn)槠鋽?shù)據(jù)結(jié)構(gòu)和我們的 注冊(cè)路由信息結(jié)構(gòu)十分接近,不需要再重新修改路由信息的數(shù)據(jù)結(jié)構(gòu),即可完美的 展現(xiàn)在 Three樹形控件里
2、將側(cè)邊導(dǎo)航所需要的路由信息對(duì)象 抽離成一個(gè)數(shù)組,根據(jù)后臺(tái)返回的數(shù)組,篩選出對(duì)應(yīng)的路由信息,通過(guò)addRoutes添加到路由信息對(duì)象里,即可完成路由信息的動(dòng)態(tài)添加
詳情
// 在router.js 路由文件 新建數(shù)組路由存儲(chǔ) '/' 父路由下的所有子路由(這里所有的動(dòng)態(tài)路由均為 '/' 的子路由)
let routerLists=[
{
id:1,
path: '',
label: '首頁(yè)',
redirect: '/index', //重定向到
meta:{
title: '首頁(yè)',
table: true,
display: false,
icon: 'el-icon-s-home'
}
},
{
id: 2,
path: '/index',
name: 'index',
label: '首頁(yè)',
component: _import('Index/Index'),
meta:{
title: '首頁(yè)',
table: true,
display:true,
icon: 'el-icon-s-home'
}
},
{
id: 3,
path: '/shop',
name: 'shop',
label: '商品管理',
component: _import('Shop/Shop'),
meta:{
title: '商品列表',
table: true,
display:true,
icon: 'el-icon-s-operation'
}
},
{
id:20,
path: '/admin',
label: '管理員列表',
component: _import('admin/index'),
meta:{
title: '管理員列表',
table: true,
display:true,
icon: 'el-icon-s-custom'
},
children:[
{
id:21,
path: '/admin/index',
label: '管理員列表',
component: _import('admin/admin'),
meta:{
title: '管理員列表',
table: true,
display:true,
icon:'el-icon-tickets'
}
},
{
id:22,
path: '/admin/adminlist',
label: '添加管理員',
component: _import('admin/adminlist'),
meta:{
title: '添加管理員',
table: true,
display:true,
icon:'el-icon-document-remove'
}
}
]
}
]
//定義 上面數(shù)組的父路由
let routerAlls=[ //這里為routerLists的父路由
{
path: '/',
component: Home
}
]
1 .權(quán)限配置表
// 先把路由信息對(duì)象字符串化,然后去除component字段 ,再傳遞給 權(quán)限配置表
let routerListString =JSON.stringify(routerLists)
let src= routerListStr(routerListString)
store.commit('serRouterList',src)
let arr=[1,2,3,20,21,22] //這里為權(quán)限列表數(shù)組(既后臺(tái)根據(jù)用戶身份返回的對(duì)應(yīng)的路由數(shù)組)
//根據(jù)權(quán)限配置表(arr數(shù)組)和動(dòng)態(tài)路由信息對(duì)象(routerLists數(shù)組) 獲取本用戶的路由信息表,并添加到 routerAlls 路由的二級(jí)路由里
2.獲取動(dòng)態(tài)路由
routerAlls[0].children = routerListFun(arr,routerLists)
//獲取 路徑 '/' 的子路由,并添加至 routerAlls 這里的 routerListFun函數(shù) 為 根據(jù)權(quán)限列表數(shù)組(arr)篩選動(dòng)態(tài)路由信息對(duì)象(routerLists) PS:函數(shù)內(nèi)容見 文章末尾:附錄
3.獲取側(cè)邊導(dǎo)航欄 的 渲染菜單 數(shù)組
//根據(jù)權(quán)限配置表數(shù)組(arr)和動(dòng)態(tài)路由信息對(duì)象(routerLists) 獲取本用戶的菜單列表
let mentParse =JSON.parse(JSON.stringify(src))
let menuList = routerListFun(arr,mentParse) //這里routerListFun函數(shù)注意去除返回?cái)?shù)組中的component
store.commit('setMents',menuList) //將其添加到vuex
// 注冊(cè)路由
let routers =new Router({
mode: 'history',
// base: process.env.BASE_URL,
routes: [
{
path: '/loading',
name: 'loading',
component: () => import('../views/Load/Loading.vue'),
meta:{
title: '登陸',
table: false
}
}
]
})
// 將篩選后的路由信息對(duì)象添加至路由表
routers.addRoutes(routerAlls)
// 進(jìn)行全局導(dǎo)航守衛(wèi)
routers.beforeEach((to,from,next)=>{
if(to.path != '/loading'){
let username=store.state.load.userList.username
if(username){
next()
}else{
next({
path:'/loading',
query:{
path:to.path
}
})
}
}else{
next()
}
})
export default routers;
附錄
1.動(dòng)態(tài)路由書寫規(guī)則
* 路由書寫規(guī)則
* 1、只有一級(jí)路由(實(shí)際為二級(jí)路由):
* {
id: 2, //ID全局不能重復(fù)
path: '/index', //路由路徑 全局不能重復(fù)
name: 'index', //名字,全局不能重復(fù),存在二級(jí)路由,則一級(jí)路由不能有名字
label: '首頁(yè)', // 頁(yè)面名稱(用于權(quán)限配置時(shí) 顯示名稱使用)
component: _import('Index/Index'), // 文件地址(此處對(duì)應(yīng)的是views目錄)
meta:{
title: '首頁(yè)', //頁(yè)面名稱(橫向teble標(biāo)簽切換)
table: true, // 是否顯示 teable 切換按鈕
display:true, // 是否在側(cè)邊導(dǎo)航菜單顯示
icon: 'el-icon-s-home' // 側(cè)邊導(dǎo)航的icon圖標(biāo)
}
}
2、包含二級(jí)路由(實(shí)際為三級(jí)路由)
{
id:20, //ID全局不能重復(fù)
path: '/admin', //路由路徑 全局不能重復(fù)(此處為父級(jí)))
label: '管理員列表', // 頁(yè)面名稱(用于權(quán)限配置時(shí) 顯示名稱使用)
component: _import('admin/index'), // 文件地址(此處對(duì)應(yīng)的是views目錄)注意:此文件下 應(yīng)包含(router-view 標(biāo)簽 來(lái)顯示子頁(yè)面)
meta:{
title: '管理員列表', //頁(yè)面名稱(橫向teble標(biāo)簽切換)
table: true,
display:true, // 是否在側(cè)邊導(dǎo)航菜單顯示(注意 這里是父級(jí),如果為false,則子級(jí)不在折疊)
icon: 'el-icon-s-custom' // 側(cè)邊導(dǎo)航的icon圖標(biāo)
},
children:[
{
id:21, //ID全局不能重復(fù)
path: '/admin/index', //路由路徑 全局不能重復(fù)(此處為父級(jí)))
label: '管理員列表', // 頁(yè)面名稱(用于權(quán)限配置時(shí) 顯示名稱使用)
component: _import('admin/admin'), // 文件地址(此處對(duì)應(yīng)的是views目錄)
meta:{
title: '管理員列表', //頁(yè)面名稱(橫向teble標(biāo)簽切換)
table: true, // 是否顯示 teable 切換按鈕
display:true, // 是否在側(cè)邊導(dǎo)航菜單顯示
icon:'el-icon-tickets' // 側(cè)邊導(dǎo)航的icon圖標(biāo)
}
}
]
}
2.routerListFun、routerListStr函數(shù)
// 根據(jù)后臺(tái)返回的權(quán)限數(shù)組,篩選對(duì)應(yīng)的路由信息對(duì)象
export function routerListFun(arr,allList){
let arrArray=[]
for(let i=0;i<arr.length;i++){
for(let k=0;k<allList.length;k++){
if(arr[i] == allList[k].id){
arrArray.push(allList[k])
}
}
}
for(let i=0;i<arrArray.length;i++){
if(arrArray[i].children && arrArray[i].children.length>0){
arrArray[i].childrens=[]
for(let k=0;k<arrArray[i].children.length;k++){
for(let j=0;j<arr.length;j++){
if(arrArray[i].children[k].id == arr[j]){
arrArray[i].childrens.push(arrArray[i].children[k])
}
}
}
arrArray[i].children=arrArray[i].childrens
}
}
return arrArray;
}
// 根據(jù)全部的路由信息對(duì)象 返回 權(quán)限列表
export function routerListStr(routerStr){
let routerJson= JSON.parse(routerStr)
for(let i=0;i<routerJson.length;i++){
if(routerJson[i].component){
routerJson[i].component=''
}
if(routerJson[i].children && routerJson[i].children.length>0){
for(let k=0;k<routerJson[i].children.length;k++){
routerJson[i].children[k].component=''
}
}
}
return routerJson;
}
3.路由渲染
<!-- 這里的 routerList 為 從 router.js動(dòng)態(tài)獲取到了路由信息 -->
<div v-for="item in routerList" :key="item.id" >
<!--包含二級(jí)導(dǎo)航-->
<el-submenu :index="item.id.toString()" v-if="item.children && item.children.length > 0 && item.meta.display==true">
<template slot="title">
<i :class="item.meta.icon"></i>
<span>{{item.label}}</span>
</template>
<el-menu-item v-show="items.meta.display" v-for="(items,indexs) in item.children" :key="indexs" :index="items.path">
<i :class="items.meta.icon"></i>
{{items.label}}
</el-menu-item>
</el-submenu>
<!-- 如果 二級(jí)導(dǎo)航的 父級(jí) 設(shè)置display:false 則直選渲染二級(jí)導(dǎo)航為一級(jí)導(dǎo)航 -->
<el-menu-item v-for="(items,indexs) in item.children" :key="indexs" :index="items.path" v-show="items.meta.display" v-else-if="item.children && item.children.length > 0 && item.meta.display==false" >
<i :class="item.meta.icon"></i>
<span slot="title">{{item.label}}</span>
</el-menu-item>
<!-- 渲染一級(jí)導(dǎo)航 -->
<el-menu-item v-show="item.meta.display" :index="item.path" v-else >
<i :class="item.meta.icon"></i>
<span slot="title">{{item.label}}</span>
</el-menu-item>
</div>