vue2模擬vue-element-admin手寫角色權限的實現
權限
路由權限
- 靜態路由:固定的路由,沒有權限。如login頁面
- 動態路由:根據不同的角色,後端返回不同的路由接口。通過meta中的roles去做篩選
store存儲路由
//地址:store/modules/permission import { routes as constantRoutes } from '@/router' // 根據meta.roles去判斷該角色是否有路由權限 function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return route.meta.roles.some(val => val === roles) } return true } /** * 遞歸動態路由 * @param routes 動態路由 * @param roles 角色 */ export function filterAsyncRoutes(routes, roles) { const res = [] routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { if (tmp.children) { //後臺傳來的路由字符串,轉換為組件對象 // let a = `../views/${route.component}`; // route.component = () => import(a); // 導入組件 tmp.children = filterAsyncRoutes(tmp.children, roles) } res.push(tmp) } }) return res } //模擬後端傳過來的路由 export const asyncRoutes = [ { path: '/', name: 'home', redirect: '/PickupTask', meta: { title: '首頁', //純前端去做動態路由 roles: ['admin'] }, component: () => import('@/views/HomeView.vue'), children: [ { path: 'PickupTask', name: 'PickupTask', meta: { title: 'PickupTask', }, component: () => import('@/views/Sd/PickupTask.vue'), }, { path: 'access', hidden: true, component: () => import('@/views/demo/Access.vue'), meta: { title: 'access', roles: ['admin'], //按鈕權限標識 button: { 'btn:access:createUser': 'hidden', 'btn:access:editUser': 'disable' }, }, }, ], } ] const permisssion = { // namespaced: true, -> store.dispatch('permisssion/generateRoutes', 'admin'); state: { //靜態路由+動態路由 routes: [], //動態路由 addRoutes: [] }, mutations: { SET_ROUTES: (state, routes) => { state.addRoutes = routes state.routes = constantRoutes.concat(routes) } }, actions: { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) commit('SET_ROUTES', accessedRoutes) resolve(accessedRoutes) }) } } } export default permisssion
router添加路由
將store中的動態路由使用addRoute添加(最新版本去掉瞭addRoutes隻能使用addRoute添加路由)。
//地址:router/index import Vue from 'vue'; import VueRouter, { RouteConfig } from 'vue-router'; import store from '@/store'; Vue.use(VueRouter); const isProd = process.env.NODE_ENV === 'production'; const routerContext = require.context('./', true, /index.js$/); //靜態路由 export let routes: any = []; routerContext.keys().forEach((route) => { // route就是路徑 // 如果是根目錄的index不做處理 if (route.startsWith('./index')) { return; } const routerModule = routerContext(route); routes = [...routes, ...(routerModule.default || routerModule)]; }); // 創建 router 實例,然後傳 `routes` 配置 const router = new VueRouter({ mode: 'history', base: isProd ? '/vue-demo/' : process.env.BASE_URL, routes, scrollBehavior(to, from, savedPosition) { if (to.hash) { return { selector: to.hash, }; } }, }); let registerRouteFresh = true; /** * 全局全局前置守衛 * to : 將要進入的目標路由對象 * from : 即將離開的目標路由對象 */ router.beforeEach(async (to: any, from, next) => { //設置當前頁的title document.title = to.meta.title; if (to.path === '/login' && localStorage.getItem('token')) { next('/'); } console.log(registerRouteFresh); //如果首次或者刷新界面,next(...to, replace: true)會循環遍歷路由, //如果to找不到對應的路由那麼他會再執行一次beforeEach((to, from, next))直到找到對應的路由, //我們的問題在於頁面刷新以後異步獲取數據,直接執行next()感覺路由添加瞭但是在next()之後執行的, //所以我們沒法導航到相應的界面。這裡使用變量registerRouteFresh變量做記錄,直到找到相應的路由以後,把值設置為false然後走else執行next(),整個流程就走完瞭,路由也就添加完瞭。 if (registerRouteFresh) { //設置路由 const accessRoutes = await store.dispatch('generateRoutes', 'admin'); let errorPage = { path: '*', name: '404', component: () => import('../views/404.vue'), }; // 將404添加進去 // 現在才添加的原因是:作為一級路由,當刷新,動態路由還未加載,路由就已經做瞭匹配,找不到就跳到瞭404 router.addRoute({ ...errorPage }); accessRoutes.forEach((item: RouteConfig) => { router.addRoute(item); }); //獲取路由配置 console.log(router.getRoutes()); //通過next({...to, replace})解決刷新後路由失效的問題 next({ ...to, replace: true }); registerRouteFresh = false; } else { next(); } next(); }); export default router;
菜單權限
路由遍歷,通過store路由權限中的permission.state.routes去做處理
按鈕權限
準備:存儲按鈕標識
//地址:store/modules/user import { userInfo, } from '@/api' const user = { state: { role: 'admin', mockButton: { 'btn:access:createUser': 'show', 'btn:access:editUser': 'show' } }, //更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation mutations: { change_role: (state, data) => { state.role = data.role }, change_btn: (state, data) => { state.mockButton = data.mockButton } }, } export default user
指令
通過模擬傳入按鈕標識的屬性,去判斷按鈕是否隱藏或者禁用
//地址:directive/permission/index import permission from './permissionBtn' const install = function(Vue) { Vue.directive('permission', permission) } if (window.Vue) { window['permission'] = permission Vue.use(install); // eslint-disable-line } permission.install = install export default permission
//地址:directive/permission/permissionBtn import store from '@/store' function checkPermission(el, binding) { const { value } = binding const roles = store.getters && store.getters.role // 獲取模擬權限按鈕標識 const mockButton = store.getters && store.getters.mockButton // 設置按鈕屬性 if (mockButton[value] === 'disabled') { el.disabled = true el.setAttribute('disabled', true) } if (mockButton[value] === 'hidden') { el.style.display = 'none' } if (mockButton[value] === 'show') { el.style.display = 'block' el.disabled = false } // throw new Error(`need roles! Like v-permission="['admin','editor']"`) } export default { inserted(el, binding) { checkPermission(el, binding) }, update(el, binding) { checkPermission(el, binding) } }
//應用
<template> <div> <a-button @click="changeRole">切換角色</a-button> <span>當前角色:{{ role }}</span> <!-- 註意一定要加disabled屬性,才能設置它的disabled值 --> <a-button :disabled="false" v-permission="'btn:access:createUser'"> 新建用戶 </a-button> <a-button :disabled="false" v-permission="'btn:access:editUser'"> 編輯用戶 </a-button> </div> </template> <script lang='ts'> import { Vue, Component, Watch } from "vue-property-decorator"; import permission from "@/directive/permission/index.js"; // 權限判斷指令 // import checkPermission from '@/utils/permission' // 權限判斷函數 @Component({ directives: { permission, }, computed: { role() { return this.$store.getters.role; }, }, }) export default class Access extends Vue { get role() { return this.$store.getters.role; } changeRole() { //設置按鈕權限 this.$store.commit("change_btn", { mockButton: this.role === "admin" ? { "btn:access:createUser": "hidden", "btn:access:editUser": "disabled", } : { "btn:access:createUser": "show", "btn:access:editUser": "show", }, }); //設置角色 this.$store.commit("change_role", { role: this.role === "admin" ? "edit" : "admin", }); } } </script>
函數
/** * @param {Array} value * @returns {Boolean} * @example see @/views/permission/directive.vue * 除瞭使用指令,也可以使用函數 */ export default function checkPermission(value) { if (value && value instanceof Array && value.length > 0) { const roles = store.getters && store.getters.roles const permissionRoles = value const hasPermission = roles.some(role => { return permissionRoles.includes(role) }) return hasPermission } console.error(`need roles! Like v-permission="['admin','editor']"`) return false }
<template> <div> <a-button v-if="hasPerms('btn:access:createUser')" :disable="hasPerms('btn:access:createUser')" > 新建用戶 </a-button> <a-button v-if="hasPerms('btn:access:editUser')" :disable="hasPerms('btn:access:editUser')" > 編輯用戶 </a-button> </div> </template> <script lang='ts'> import { Vue, Component, Watch } from "vue-property-decorator"; import checkPermission from "@/utils/permission"; // 權限判斷函數 @Component export default class Access extends Vue { hasPerms(params) { return checkPermission(params); } } </script>
到此這篇關於vue2模擬vue-element-admin手寫角色權限的實現的文章就介紹到這瞭,更多相關vue2 角色權限內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- vue實現動態路由詳細
- 使用vue-element-admin框架從後端動態獲取菜單功能的實現
- 深入解析vue中的權限管理
- 詳解如何使用Vuex實現Vue後臺管理中的角色鑒權
- vue3中vue-meta的使用方法解析