默认挂载不须要权限的路由,例如:登陆、主页。须要权限的页面经过 router.addRoutes(点击查看官方文档) 动态添加更多的路由规则,404拦截页面须要放在路由表的最后,不然 /404 后面的路由会被404拦截,经过路由元信息meta(点击查看官方文档)记录路由须要的权限。为了菜单列表能够被翻译,路由表的 name 属性值经过 i18n 的英文对照表来获取,也能够直接写英文名称,如 name: routeNmae.builtInIcon
能够直接写成 name: "builtInIcon"
,凭我的喜爱html
// src/router/index.js import en from '../i18n/lang/en' // 路由名字 name 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 // 不须要权限的路由 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: '*', 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>