vue基于Element按鈕權(quán)限實(shí)現(xiàn)方案
背景需求:ERP系統(tǒng)需增加 ”按鈕權(quán)限控制“ 功能,對(duì)權(quán)限的控制粒度要普及到按鈕層級(jí)。
預(yù)期
按鈕權(quán)限控制的交互方式無(wú)非兩種:"不可見(jiàn)" 和 "可見(jiàn)不可點(diǎn)"。
不可見(jiàn)
不可見(jiàn)的交互方式相對(duì)簡(jiǎn)單,我們可使用 v-if 控制其是否顯示。使用 v-show 也行,但不夠保險(xiǎn),畢竟 v-show 只是把樣式改成 display: none,在真實(shí)的 DOM 渲染還是存在的,所以更推薦 v-if 來(lái)控制不可見(jiàn)。
可見(jiàn)不可點(diǎn)
“看是能看了,但你不行了”。
- 樣式控制(得加個(gè)禁用樣式),什么 cursor: not-allowed ,置灰之類(lèi)的云云;
- 不可點(diǎn)擊,即要禁用或屏蔽點(diǎn)擊事件,好像有 preventDefault/stopProgration 可實(shí)現(xiàn);
最終產(chǎn)品需求選擇了 “可見(jiàn)不可點(diǎn)”,原因可能就覺(jué)得不可見(jiàn)太簡(jiǎn)單了。(¬_¬)
思路探索
- 給按鈕點(diǎn)擊事件的回調(diào)函數(shù),加個(gè)包裝函數(shù),對(duì)其權(quán)限控制,進(jìn)行事件攔截與觸發(fā)。相當(dāng)是做了個(gè)代理,有點(diǎn)高階組件那意思(但對(duì)現(xiàn)有業(yè)務(wù)改動(dòng)太大,得對(duì)每個(gè)@click綁定函數(shù)逐個(gè)修改,遂放棄該方案);
- 阻止按鈕點(diǎn)擊事件冒泡與觸發(fā),貌似能用上 preventDefautl/stopProgration, 感覺(jué)能用指令的方式對(duì) DOM 元素進(jìn)行事件監(jiān)聽(tīng),允許的話則讓事件正常執(zhí)行,不允許則攔截屏蔽;
實(shí)踐方案
最終選擇了指令的方式,最小成本擴(kuò)展,避免改動(dòng)現(xiàn)有業(yè)務(wù)代碼邏輯。
針對(duì)權(quán)限控制需做點(diǎn)擊劫持的元素:
- el-button
- btn-wrapper(自封裝組件)
- div/span/a 等標(biāo)簽
具體實(shí)現(xiàn)方案請(qǐng)看下文:
權(quán)限入口:Vuex 控制,全局使用
// 用戶登陸后,獲取該用戶權(quán)限 CODE 碼,并存儲(chǔ)至 store
this.$store.commit('SET_AUTH_CODE', authCodeList);
SET_AUTH_CODE: (state, acthCode) => {
if (acthCode) {
state.autoCodeList = acthCode;
}
setStore({
name: 'autoCodeList',
content: state.autoCodeList || [],
});
}
定義權(quán)限指令
const disableClickFn = (event) => {
event && event.stopImmediatePropagation();
}
export const hasPermission = () => {
Vue.directive('permission', {
bind(el, binding) {
let disalbe = true;
if (autoCodeList.length && autoCodeList.includes(binding.value)) {
disable = false;
}
if (disable) {
el.classList.add('permission-disabled');
el.setAttribute('disabled', 'disabled');
el.addEventListener('click', disableClickFn, true);
}
},
unbind(el) {
el.removeEventListener('click', disableClickFn);
}
});
};
- 首先 addEventListener 第三個(gè)參數(shù)我們使用 useCapture 為 true 讓其在捕獲階段觸發(fā),因此這里的事件監(jiān)聽(tīng)器會(huì)優(yōu)先 @click 觸發(fā)回調(diào);
- 其次使用了 stopImmediatePropagation 阻止事件冒泡和其它相同事件監(jiān)聽(tīng)器的觸發(fā);
如果多個(gè)事件監(jiān)聽(tīng)器被附加到相同元素的相同事件類(lèi)型上,當(dāng)此事件觸發(fā)時(shí),它們會(huì)按其被添加的順序被調(diào)用。如果在其中一個(gè)事件監(jiān)聽(tīng)器中執(zhí)行 stopImmediatePropagation() ,那么剩下的事件監(jiān)聽(tīng)器都不會(huì)被調(diào)用。MSDN - stopImmediatePropagation
增加禁用的 CSS 樣式
.permission-disabled {
position: relative;
cursor: not-allowed !important;
pointer-events: none; // 阻止元素成為鼠標(biāo)事件
border:none;
background-image: none;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 0px;
right: 0px;
height: 100%;
z-index: 9;
background: rgba(255, 255, 255, 0.5);
}
}
這里使用了一個(gè)比較陌生的 CSS 屬性, pointer-events。
CSS3 的 pointer-events 屬性指定在什么情況下 (如果有) 某個(gè)特定的圖形元素可以成為鼠標(biāo)事件的 target。 更多用法參考:MSDN - pointer-events
這里使用 pointer-events 只是一個(gè)輔助功能,并不一定意味著元素上的事件監(jiān)聽(tīng)器永遠(yuǎn)不會(huì)觸發(fā),如果后代元素有指定 pointer-events 并允許成為事件目標(biāo)的話,是可以觸發(fā)父元素事件,而且單純依靠 CSS 屬性來(lái)控制不點(diǎn)擊,還是有風(fēng)險(xiǎn),因此這里僅作輔助作用。
全局 "權(quán)限判斷" 工具函數(shù)
import { getStore, } from '@/util/store';
const autoCodeList = getStore({ name: 'autoCodeList', }) || [];
export function hasPermission(authName) {
return !(autoCodeList.length > 0 && autoCodeList.includes(authName));
}
具體使用
// 指令方式(這里的 oms/order/save 就是對(duì)應(yīng)用戶登陸時(shí) CODE 權(quán)限碼)
<el-button v-permission="'oms:order:save'">保存</el-button>
// 函數(shù)方式
<el-button :disabled="hasPermission('oms:order:save')"></el-button>
到此這篇關(guān)于vue基于Element按鈕權(quán)限實(shí)現(xiàn)方案的文章就介紹到這了,更多相關(guān)Element 按鈕權(quán)限內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue中兩種生成二維碼(帶logo)并下載方式總結(jié)
與后端生成二維碼相比,前端生成二維碼更具有靈活性,下面這篇文章主要給大家介紹了關(guān)于Vue中兩種生成二維碼(帶logo)并下載的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
vue項(xiàng)目中如何將數(shù)據(jù)導(dǎo)出為word文檔
這篇文章主要介紹了vue項(xiàng)目中如何將數(shù)據(jù)導(dǎo)出為word文檔問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
element-ui 設(shè)置菜單欄展開(kāi)的方法
今天小編就為大家分享一篇element-ui 設(shè)置菜單欄展開(kāi)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
Vue項(xiàng)目如何設(shè)置反向代理和cookie設(shè)置問(wèn)題
這篇文章主要介紹了Vue項(xiàng)目如何設(shè)置反向代理和cookie設(shè)置問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue使用distpicker插件實(shí)現(xiàn)省市級(jí)下拉框三級(jí)聯(lián)動(dòng)
這篇文章主要介紹了Vue使用distpicker插件實(shí)現(xiàn)省市級(jí)下拉框三級(jí)聯(lián)動(dòng),比如通過(guò)JSON文件生成對(duì)應(yīng)的區(qū)域下拉框,element-china-are插件,包括distpicker插件,通過(guò)代碼講解如何使用distpicker插件實(shí)現(xiàn)省市級(jí)三聯(lián)跳動(dòng),需要的朋友可以參考下2023-02-02
vue,uniapp--js禁止頁(yè)面滾動(dòng),取消滾動(dòng)方式
這篇文章主要介紹了vue,uniapp--js禁止頁(yè)面滾動(dòng),取消滾動(dòng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
解決vue-cli項(xiàng)目開(kāi)發(fā)運(yùn)行時(shí)內(nèi)存暴漲卡死電腦問(wèn)題
最近開(kāi)發(fā)一個(gè)vue項(xiàng)目時(shí)遇到電腦卡死問(wèn)題,突然間系統(tǒng)就非常卡,然后卡著卡著就死機(jī)了,鼠標(biāo)也動(dòng)不了了,只能冷啟動(dòng)。這篇文章主要介紹了vue-cli項(xiàng)目開(kāi)發(fā)運(yùn)行時(shí)內(nèi)存暴漲卡死電腦問(wèn)題,需要的朋友可以參考下2019-10-10
利用webstrom調(diào)試Vue.js單頁(yè)面程序的方法教程
這篇文章主要給大家介紹了利用webstrom調(diào)試Vue.js單頁(yè)面程序的方法教程,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧。2017-06-06

