默認掛載不須要權限的路由,例如:登陸、主頁。須要權限的頁面經過 router.addRoutes(點擊查看官方文檔) 動態添加更多的路由規則,404攔截頁面須要放在路由表的最後,不然 /404 後面的路由會被404攔截,經過路由元信息meta(點擊查看官方文檔)記錄路由須要的權限。爲了菜單列表能夠被翻譯,路由表的 name 屬性值經過 i18n 的英文對照表來獲取,也能夠直接寫英文名稱,如 name: routeNmae.builtInIcon
能夠直接寫成 name: "builtInIcon"
,憑我的喜愛html
// src/router/index.js
import en from '../i18n/lang/en' // 英文對照表
import Vue from 'vue'
import Router from 'vue-router'
import CommerViews from '@/views/commerViews'
import Login from '@/views/login/index'
import Layout from '@/views/layout/layout'
import HomeMain from '@/views/index/mainIndex'
// 不是必須加載的組件使用懶加載
const Icon = () => import('@/views/icon/index')
const Upload = () => import('@/views/upload/upload')
const Markdown = () => import('@/views/markdown/markdownView')
const NotFound = () => import('@/page404')
Vue.use(Router)
let routeNmae = en.routeNmae // 從英文翻譯對照表獲取路由的英文名字,當作路由'name'屬性的值
// 不須要權限的路由
let defaultRouter = [
{ path: '/',
redirect: '/index',
hidden: true,
children: []
},
{
path: '/login',
component: Login,
name: '',
hidden: true,
children: []
},
{
path: '/index',
iconCls: 'fa fa-dashboard', // 菜單圖標,直接填寫字體圖標的 class
name: routeNmae.home,
component: Layout,
alone: true,
children: [
{
path: '/index',
iconCls: 'fa fa-dashboard',
name: '主頁',
component: HomeMain,
children: []
}
]
},
{
path: '/404',
component: NotFound,
name: '404',
hidden: true,
children: []
},
]
// 須要 addRouters 動態加載的路由
let addRouter = [
{
path: '/',
iconCls: 'fa fa-server',
name: routeNmae.multiDirectory,
component: Layout,
children: [
{
path: '/erji1',
iconCls: 'fa fa-server',
name: routeNmae['menu2-1'],
component: Erji,
children: []
},
{
path: '/erji3',
iconCls: 'fa fa-server',
name: routeNmae['menu2-3'],
component: CommerViews, // 無限極菜單的容器 超過三級菜單父級容器須要使用 CommerViews
children: [
{
path: '/sanji2',
iconCls: 'fa fa-server',
name: routeNmae['menu3-2'],
component: Sanji2,
children: []
},
{
path: '/sanji3',
iconCls: 'fa fa-server',
name: routeNmae['menu3-3'],
component: CommerViews,
children: [
{
path: '/siji',
iconCls: 'fa fa-server',
name: routeNmae['menu4-1'],
component: Siji,
children: []
},
{
path: '/siji1',
iconCls: 'fa fa-server',
name: routeNmae['menu4-2'],
component: CommerViews,
children: [
{
path: '/wuji',
iconCls: 'fa fa-server',
name: routeNmae['menu5-1'],
component: Wuji,
children: []
}
]
}
]
}
]
}
]
},
{
path: '/',
iconCls: 'el-icon-edit', // 圖標樣式class
name: routeNmae.editor,
component: Layout,
meta: {role: ['superAdmin', 'admin']}, // 須要權限 'superAdmin', 'admin'。meta屬性能夠放在父級,驗證父級和全部子菜單,也能夠放在子級單獨驗證某一個子菜單
children: [
{
path: '/markdown',
iconCls: 'fa fa-file-code-o', // 圖標樣式class
name: routeNmae.markdown,
component: Markdown,
children: []
}
]
},
{ path: '*', // 通配符攔截放在最後,不存在的路由全都指向404頁面
redirect: '/404',
hidden: true,
children: []
},
]
export default new Router({
routes: defaultRouter
})
export {defaultRouter, addRouter}
複製代碼
而後經過 token
獲取當前登陸用戶的我的信息,在router
被掛載到Vue以前和須要權限的路由表作對比,篩選出當前角色有權限訪問的動態路由表,vue
// main.js
// 獲取角色信息,根據用戶權限動態加載路由
router.beforeEach((to, from, next) => {
if (store.getters.token) { // 查看 token 是否存在
store.dispatch('setToken', store.getters.token) // 每次操做都從新寫入 token,更新有效會話時長
if (to.path === '/login') {
next({path: '/'})
} else {
if (!store.getters.info.role) { // 查看是否有當前用戶角色,若是沒有則獲取角色信息
!async function getAddRouters () {
await store.dispatch('getInfo', store.getters.token) // 經過token獲取角色信息
await store.dispatch('newRoutes', store.getters.info.role) // 經過權限篩選新路由表
await router.addRoutes(store.getters.addRouters) // 動態加載新路由表
next({path: '/index'})
}()
} else {
let is404 = to.matched.some(record => { // 404頁面攔截
if(record.meta.role){
// 沒有權限的頁面,跳轉的404頁面
return record.meta.role.indexOf(store.getters.info.role) === -1
}
})
if(is404){
next({path: '/404'})
return false
}
next()
}
}
} else {
if (to.path === '/login') {
next()
}
next({path: '/login'})
}
})
複製代碼
// src/vuex/modules/role.js
state: {
info: '' // 每次刷新都要經過token請求我的信息來篩選動態路由
},
mutations: {
getInfo (state, token) {
// 省略 axios 請求代碼 經過 token 向後臺請求用戶權限等信息,這裏用假數據賦值
state.info = {
role: 'superAdmin',
permissions: '超級管理員'
}
// 將 info 存儲在 sessionStorage裏, 按鈕指令權限將會用到
sessionStorage.setItem('info', JSON.stringify(store.getters.info))
},
setRole (state, options) { // 切換角色,測試權限管理
state.info = {
role: options.role,
permissions: options.permissions
}
sessionStorage.setItem('info', JSON.stringify(store.getters.info));
// 權限切換後要根據新權限從新獲取新路由,再走一遍流程
store.dispatch('newRoutes', options.role)
router.addRoutes(store.getters.addRouters)
}
},
actions: {
getInfo ({commit}, token) {
commit('getInfo', token)
},
setRole ({commit}, options){// 切換角色,測試權限管理,不須要能夠刪除
commit('setRole', options)
}
}
複製代碼
// src/vuex/modules/routerData.js
import {defaultRouter, addRouter} from '@/router/index'
const routerData = {
state: {
routers: [],
addRouters: []
},
mutations: {
setRouters: (state, routers) => {
state.addRouters = routers // 保存動態路由用來addRouter
state.routers = defaultRouter.concat(routers) // 全部有權限的路由表,用來生成菜單列表
}
},
actions: {
newRoutes ({commit}, role) {
// 經過遞歸路由表,刪除掉沒有權限的路由
function eachSelect (routers, userRole) {
for (let j = 0; j < routers.length; j++) {
if (routers[j].meta && routers[j].meta.role.length && routers[j].meta.role.indexOf(userRole) === -1) {
// 若是沒有權限就刪除該路由,若是是父級路由沒權限,全部子菜單就更沒權限了,因此一併刪除
routers.splice(j, 1)
j = j !== 0 ? j - 1 : j // 刪除掉沒有權限的路由後,下標應該中止 +1,保持不變,若是下標是 0的話刪除以後依然等於0
}
if (routers[j].children && routers[j].children.length) {
// 若是包含子元素就遞歸執行
eachSelect(routers[j].children, userRole)
}
}
}
// 拷貝這個數組是由於作權限測試的時候能夠從低級切回到高級角色,僅限演示,正式開發時省略這步直接使用 addRouter
// 僅限演示
let newArr = [...addRouter]
eachSelect(newArr, role)
commit('setRouters', newArr)
// 正式開發
// eachSelect(addRouter, role)
// commit('setRouters', addRouter)
}
}
}
export default routerData
複製代碼
經過自定義指令獲取當前按鈕所需的有哪些權限,而後和當前用戶的權限對比,若是沒有權限則刪除按鈕ios
// btnPermission.js
import Vue from 'vue'
Vue.directive('roleBtn',{
bind:function (el,binding) {
let roleArr = binding.value; // 獲取按鈕所需權限
let userRole = JSON.parse(sessionStorage.getItem('info')).role // 獲取當前用戶權限
if (roleArr && roleArr.indexOf(userRole) !== -1) {
return false
} else {
el.parentNode.removeChild(el);
}
}
})
export default Vue
複製代碼
<el-button type="primary" plain size="medium">查看</el-button>
<el-button type="primary" plain size="medium" v-role-btn="['admin']">添加</el-button>
<el-button type="danger" plain size="medium" v-role-btn="['superAdmin']">刪除</el-button>
<el-button type="primary" plain size="medium" v-role-btn="['superAdmin','admin']">修改</el-button>
複製代碼
Vue2.0 + ElementUI 手寫權限管理系統後臺模板(一)——簡述vue-router
Vue2.0 + ElementUI 手寫權限管理系統後臺模板(二)——權限管理vuex