vue2模擬vue-element-admin手寫角色權(quán)限的實(shí)現(xiàn)
權(quán)限
路由權(quán)限
- 靜態(tài)路由:固定的路由,沒(méi)有權(quán)限。如login頁(yè)面
- 動(dòng)態(tài)路由:根據(jù)不同的角色,后端返回不同的路由接口。通過(guò)meta中的roles去做篩選
store存儲(chǔ)路由
//地址: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
}
?
/**
* 遞歸動(dòng)態(tài)路由
* @param routes 動(dòng)態(tài)路由
* @param roles 角色
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
//后臺(tái)傳來(lái)的路由字符串,轉(zhuǎn)換為組件對(duì)象
// let a = `../views/${route.component}`;
// route.component = () => import(a); // 導(dǎo)入組件
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
?
return res
}
?
//模擬后端傳過(guò)來(lái)的路由
export const asyncRoutes = [
{
path: '/',
name: 'home',
redirect: '/PickupTask',
meta: {
title: '首頁(yè)',
//純前端去做動(dòng)態(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)識(shí)
button: {
'btn:access:createUser': 'hidden',
'btn:access:editUser': 'disable'
},
},
},
],
}
]
?
const permisssion = {
// namespaced: true, -> store.dispatch('permisssion/generateRoutes', 'admin');
state: {
//靜態(tài)路由+動(dòng)態(tài)路由
routes: [],
//動(dòng)態(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 permisssionrouter添加路由
將store中的動(dòng)態(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)路由對(duì)象
* from : 即將離開的目標(biāo)路由對(duì)象
*/
router.beforeEach(async (to: any, from, next) => {
//設(shè)置當(dāng)前頁(yè)的title
document.title = to.meta.title;
if (to.path === '/login' && localStorage.getItem('token')) {
next('/');
}
console.log(registerRouteFresh);
//如果首次或者刷新界面,next(...to, replace: true)會(huì)循環(huán)遍歷路由,
//如果to找不到對(duì)應(yīng)的路由那么他會(huì)再執(zhí)行一次beforeEach((to, from, next))直到找到對(duì)應(yīng)的路由,
//我們的問(wèn)題在于頁(yè)面刷新以后異步獲取數(shù)據(jù),直接執(zhí)行next()感覺(jué)路由添加了但是在next()之后執(zhí)行的,
//所以我們沒(méi)法導(dǎo)航到相應(yīng)的界面。這里使用變量registerRouteFresh變量做記錄,直到找到相應(yīng)的路由以后,把值設(shè)置為false然后走else執(zhí)行next(),整個(gè)流程就走完了,路由也就添加完了。
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)在才添加的原因是:作為一級(jí)路由,當(dāng)刷新,動(dòng)態(tài)路由還未加載,路由就已經(jīng)做了匹配,找不到就跳到了404
router.addRoute({ ...errorPage });
accessRoutes.forEach((item: RouteConfig) => {
router.addRoute(item);
});
//獲取路由配置
console.log(router.getRoutes());
//通過(guò)next({...to, replace})解決刷新后路由失效的問(wèn)題
next({ ...to, replace: true });
registerRouteFresh = false;
} else {
next();
}
next();
});
?
export default router;菜單權(quán)限
路由遍歷,通過(guò)store路由權(quán)限中的permission.state.routes去做處理
按鈕權(quán)限
準(zhǔn)備:存儲(chǔ)按鈕標(biāo)識(shí)
//地址: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指令
通過(guò)模擬傳入按鈕標(biāo)識(shí)的屬性,去判斷按鈕是否隱藏或者禁用
//地址: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)識(shí)
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli 使用axios的操作方法及整合axios的多種方法
這篇文章主要介紹了vue-cli 使用axios的操作方法及整合axios的多種方法,vue-cli整合axios的多種方法,小編一一給大家列出來(lái)了,大家根據(jù)自身需要選擇,需要的朋友可以參考下2018-09-09
vue復(fù)合組件實(shí)現(xiàn)注冊(cè)表單功能
這篇文章主要為大家詳細(xì)介紹了vue復(fù)合組件實(shí)現(xiàn)注冊(cè)表單功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
拿來(lái)就用vue-gird-layout組件封裝示例
這篇文章主要介紹了vue-gird-layout組件封裝示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
vue router 跳轉(zhuǎn)后回到頂部的實(shí)例
今天小編就為大家分享一篇vue router 跳轉(zhuǎn)后回到頂部的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated
安裝vue腳手架報(bào)錯(cuò)可能具體原因比較多,可以根據(jù)報(bào)錯(cuò)信息進(jìn)行排查,本文主要介紹了npm安裝vue腳手架報(bào)錯(cuò)警告npm WARN deprecated,感興趣的可以了解一下2023-11-11
el-table渲染慢卡頓問(wèn)題最優(yōu)解決方案
本文主要介紹了el-table渲染慢卡頓問(wèn)題最優(yōu)解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
vue-element-admin搭建后臺(tái)管理系統(tǒng)的實(shí)現(xiàn)步驟
本文主要介紹了vue-element-admin搭建后臺(tái)管理系統(tǒng)的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10

