vue2模擬vue-element-admin手寫角色權(quán)限的實(shí)現(xiàn)
權(quán)限
路由權(quán)限
- 靜態(tài)路由:固定的路由,沒有權(quán)限。如login頁面
- 動態(tài)路由:根據(jù)不同的角色,后端返回不同的路由接口。通過meta中的roles去做篩選
store存儲路由
//地址:store/modules/permission import { routes as constantRoutes } from '@/router' ? // 根據(jù)meta.roles去判斷該角色是否有路由權(quán)限 function hasPermission(roles, route) { if (route.meta && route.meta.roles) { return route.meta.roles.some(val => val === roles) } return true } ? /** * 遞歸動態(tài)路由 * @param routes 動態(tài)路由 * @param roles 角色 */ export function filterAsyncRoutes(routes, roles) { const res = [] routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { if (tmp.children) { //后臺傳來的路由字符串,轉(zhuǎn)換為組件對象 // let a = `../views/${route.component}`; // route.component = () => import(a); // 導(dǎo)入組件 tmp.children = filterAsyncRoutes(tmp.children, roles) } res.push(tmp) } }) ? return res } ? //模擬后端傳過來的路由 export const asyncRoutes = [ { path: '/', name: 'home', redirect: '/PickupTask', meta: { title: '首頁', //純前端去做動態(tài)路由 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'], //按鈕權(quán)限標(biāo)識 button: { 'btn:access:createUser': 'hidden', 'btn:access:editUser': 'disable' }, }, }, ], } ] ? const permisssion = { // namespaced: true, -> store.dispatch('permisssion/generateRoutes', 'admin'); state: { //靜態(tài)路由+動態(tài)路由 routes: [], //動態(tài)路由 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中的動態(tài)路由使用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$/); //靜態(tài)路由 export let routes: any = []; ? routerContext.keys().forEach((route) => { // route就是路徑 // 如果是根目錄的index不做處理 if (route.startsWith('./index')) { return; } const routerModule = routerContext(route); routes = [...routes, ...(routerModule.default || routerModule)]; }); ? // 創(chuàng)建 router 實(shí)例,然后傳 `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; /** * 全局全局前置守衛(wèi) * to : 將要進(jìn)入的目標(biāo)路由對象 * from : 即將離開的目標(biāo)路由對象 */ router.beforeEach(async (to: any, from, next) => { //設(shè)置當(dāng)前頁的title document.title = to.meta.title; if (to.path === '/login' && localStorage.getItem('token')) { next('/'); } console.log(registerRouteFresh); //如果首次或者刷新界面,next(...to, replace: true)會循環(huán)遍歷路由, //如果to找不到對應(yīng)的路由那么他會再執(zhí)行一次beforeEach((to, from, next))直到找到對應(yīng)的路由, //我們的問題在于頁面刷新以后異步獲取數(shù)據(jù),直接執(zhí)行next()感覺路由添加了但是在next()之后執(zhí)行的, //所以我們沒法導(dǎo)航到相應(yīng)的界面。這里使用變量registerRouteFresh變量做記錄,直到找到相應(yīng)的路由以后,把值設(shè)置為false然后走else執(zhí)行next(),整個流程就走完了,路由也就添加完了。 if (registerRouteFresh) { //設(shè)置路由 const accessRoutes = await store.dispatch('generateRoutes', 'admin'); let errorPage = { path: '*', name: '404', component: () => import('../views/404.vue'), }; // 將404添加進(jìn)去 // 現(xiàn)在才添加的原因是:作為一級路由,當(dāng)刷新,動態(tài)路由還未加載,路由就已經(jīng)做了匹配,找不到就跳到了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;
菜單權(quán)限
路由遍歷,通過store路由權(quán)限中的permission.state.routes去做處理
按鈕權(quán)限
準(zhǔn)備:存儲按鈕標(biāo)識
//地址:store/modules/user import { userInfo, } from '@/api' ? const user = { state: { role: 'admin', mockButton: { 'btn:access:createUser': 'show', 'btn:access:editUser': 'show' } }, //更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation mutations: { change_role: (state, data) => { state.role = data.role }, change_btn: (state, data) => { state.mockButton = data.mockButton } }, } ? export default user
指令
通過模擬傳入按鈕標(biāo)識的屬性,去判斷按鈕是否隱藏或者禁用
//地址: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 // 獲取模擬權(quán)限按鈕標(biāo)識 const mockButton = store.getters && store.getters.mockButton // 設(shè)置按鈕屬性 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) } }
//應(yīng)用
<template> <div> <a-button @click="changeRole">切換角色</a-button> <span>當(dāng)前角色:{{ role }}</span> <!-- 注意一定要加disabled屬性,才能設(shè)置它的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"; // 權(quán)限判斷指令 // import checkPermission from '@/utils/permission' // 權(quán)限判斷函數(shù) @Component({ directives: { permission, }, computed: { role() { return this.$store.getters.role; }, }, }) export default class Access extends Vue { get role() { return this.$store.getters.role; } ? changeRole() { //設(shè)置按鈕權(quán)限 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", }, }); //設(shè)置角色 this.$store.commit("change_role", { role: this.role === "admin" ? "edit" : "admin", }); } } </script>
函數(shù)
/** * @param {Array} value * @returns {Boolean} * @example see @/views/permission/directive.vue * 除了使用指令,也可以使用函數(shù) */ 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"; // 權(quán)限判斷函數(shù) @Component export default class Access extends Vue { hasPerms(params) { return checkPermission(params); } } </script>
到此這篇關(guān)于vue2模擬vue-element-admin手寫角色權(quán)限的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue2 角色權(quán)限內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli 使用axios的操作方法及整合axios的多種方法
這篇文章主要介紹了vue-cli 使用axios的操作方法及整合axios的多種方法,vue-cli整合axios的多種方法,小編一一給大家列出來了,大家根據(jù)自身需要選擇,需要的朋友可以參考下2018-09-09vue復(fù)合組件實(shí)現(xiàn)注冊表單功能
這篇文章主要為大家詳細(xì)介紹了vue復(fù)合組件實(shí)現(xiàn)注冊表單功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11vue router 跳轉(zhuǎn)后回到頂部的實(shí)例
今天小編就為大家分享一篇vue router 跳轉(zhuǎn)后回到頂部的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08npm安裝vue腳手架報錯警告npm WARN deprecated
安裝vue腳手架報錯可能具體原因比較多,可以根據(jù)報錯信息進(jìn)行排查,本文主要介紹了npm安裝vue腳手架報錯警告npm WARN deprecated,感興趣的可以了解一下2023-11-11vue-element-admin搭建后臺管理系統(tǒng)的實(shí)現(xiàn)步驟
本文主要介紹了vue-element-admin搭建后臺管理系統(tǒng)的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10