Vue自定義指令使用場(chǎng)景

當(dāng)你第一次接觸vue的時(shí)候,一定會(huì)使用到其中幾個(gè)指令,比如:v-if、v-for、v-bind...這些都是vue為我們寫(xiě)好的,用起來(lái)相當(dāng)?shù)乃?。如果有些?chǎng)景不滿(mǎn)足,需要我們自己去自定義,那要怎么辦呢?下面來(lái)一步步學(xué)習(xí)如何自定義一個(gè)屬性我們自己的指令。

什么是vue指令?

指令是可以寫(xiě)在DOM元素的小命令,他們以v-為前綴,vue就能識(shí)別這是一個(gè)指令并保持語(yǔ)法的一致性。如果你需要對(duì)HTML進(jìn)行底層操作的話(huà),這種方式是非常有用。

下面介紹幾種指令的使用方式及示例,用example代替了實(shí)際的指令。

v-example:實(shí)例化一個(gè)指令,但這個(gè)指令沒(méi)有參數(shù)。如果不傳參數(shù)會(huì)比較不靈活,但是這樣就已經(jīng)操作DOM元素的能力了。

v-example=“value”:這樣可以傳值到指令中,指令會(huì)根據(jù)value值來(lái)操作html

<div v-if="stateExample">stateExample為true時(shí)會(huì)顯示</div>

v-example="string":使用字符串作為表達(dá)式。

<p v-html="'<strong>this is an example of a string in some text <strong>'"></p>

v-example:arg="value":這里可以傳參數(shù)(arg),在下面的例子中,我們綁定一個(gè)class,然后給這個(gè)class設(shè)置樣式

<div v-bind:class="someClassObject"></div>

v-example:arg.modifier="value":使用修飾符(modifier),下面的例子可以在click事件上調(diào)用preventDefault()。

<button v-on:submit.prevent="onSubmit"></button>

vue自定義指令的基礎(chǔ)知識(shí)

現(xiàn)在對(duì)指令有了大概的了解后,我們?cè)賮?lái)學(xué)習(xí)一下如何創(chuàng)建一個(gè)自定義指令。

鉤子函數(shù)

一個(gè)指令定義對(duì)象可以提供如下幾個(gè)鉤子函數(shù)(均為可選)

bind:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用。在這里可以進(jìn)行一次性的初始化設(shè)置。

inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(僅保證父節(jié)點(diǎn)存在,但不一定已被插入文檔中)。

update:所在組件中的VNode更新時(shí)調(diào)用,但是可能發(fā)生在其子VNode更新之前。指令的值可能發(fā)生了改變,也可能沒(méi)用。但是你可以通過(guò)比較更新簽后的值來(lái)忽略不必要的模板更新

componentUpdated:指令所在組件的VNode及其子VNode全部更新后調(diào)用。

unbind:只調(diào)用一次,指令與元素解綁時(shí)調(diào)用。

接下來(lái)我們來(lái)看一下鉤子函數(shù)的參數(shù)(即el、binding、vnode和oldVnode)。

鉤子函數(shù)參數(shù)

指令鉤子函數(shù)會(huì)被傳入以下參數(shù):

el:指令所綁定的元素,可以用來(lái)直接操作DOM。

binding:一個(gè)對(duì)象,包含以下屬性:

name:指令名,不包括v-前綴。

value:指令的綁定值,例如v-my-directive="1+1"中,綁定之為2

oldValue:指令綁定的前一個(gè)值,僅在update和componentUpdated鉤子中可用。無(wú)論值是否改變都可用。

expression:字符串形式的指令表達(dá)式。例如v-my-directive:"1+1"中,表達(dá)式為“1+1”.

args:傳給指令的參數(shù),可選。例如v-my-directive:foo中,參數(shù)為“foo”

modifiers:一個(gè)包含修飾符的對(duì)象。例如:v-my-directive.foo.bar中,修飾符對(duì)象為{foo:true,bar:true}

vnode:Vue編譯的虛擬節(jié)點(diǎn)。移步VNodeAPI來(lái)了解更多詳情

oldVnode:上一個(gè)虛擬節(jié)點(diǎn),僅在update和componentUpdated鉤子中可用。

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>

Vue.directive('demo',{

bind:function(el,binding,vnode){

var s=JSON.stringify

el.innerHTML=

"name:"+s(binding.name)+'<br>'+

'value:'+s(binding.value)+'<br>+

'expression:''+s(binding.expression)+'<br>'+

"argument:"+s(binding.arg)+'<br>'+

'vnode keys:'+Object.keys(vnode).join(",")+

}

})

new Vue({

el:"#hook-arguments-example,

data:{

message:'hello!'}

})

函數(shù)簡(jiǎn)寫(xiě)

在很多時(shí)候,你可能想在bind和update時(shí)觸發(fā)相同行為,而不關(guān)心其他的鉤子。比如這樣寫(xiě):

Vue.directive('color-swatch',function(el,binding){

? ? el.style.backgroundColor=binding.value

})

對(duì)象字面量

如果指令需要多個(gè)值,可以傳入一個(gè)JavaScript對(duì)象字面量。記住,指令函數(shù)能夠接受所有的合法的JavaScript表達(dá)式

<div v-demo="{color:'white',text:'hello'}"></div>

Vue.directive('demo',function(el,binding){

console.log(binding.value.color)//=>"white"

console.log(binding.value.text)//=>"hello!"

})

vue自定義指令的使用場(chǎng)景

在Vue2.0中,代碼復(fù)用和抽象的主要形式是組件。然而,有的情況下,你仍然需要對(duì)普通dom元素進(jìn)行底層操作,這時(shí)候就會(huì)用到自定義指令。下面就來(lái)看看vue自定義指令有哪些使用場(chǎng)景。

Vue.directive('focus',{

inserted:function(el){

?el.focus();

}

})

一鍵copy的功能

1.首先建一個(gè)js文件(v-copy.js)。定義一個(gè)對(duì)象。(指令實(shí)際上就是一個(gè)對(duì)象)

important {Message} from 'ant-design-vue';

const vCopy={

/*

bind鉤子函數(shù),第一次綁定時(shí)調(diào)用,可以在這里做初始化設(shè)置

el:作用的dom對(duì)象

value:傳給指令的值,也就是我們要copy的值

}*/

bind(el,{value}){

?el.$value=value;//用一個(gè)全局屬性來(lái)存進(jìn)來(lái)的值,因?yàn)檫@個(gè)值在別的鉤子函數(shù)還會(huì)用到

el.handler=()=>{

if(!el.$value){

//值為空的時(shí)候,給出提示,我這里的提示是用的ant-design-vue的提示,你們隨意

Message.warning("無(wú)復(fù)制內(nèi)容");

return;

}

const textarea=document.createElement('textarea');

textarea.readOnly='readonly';

textarea.style.position='absolute';

textarea.style.left="-9999px";

//將要copy的值賦給textarea標(biāo)簽的value屬性

textarea.value=el.$value;

document.body.appendChild(textarea);

//選中值并復(fù)制

textarea.select();

const result=document.execCommand('Copy');

if(result){

Message.success("復(fù)制成功");

}

document.body.removeChild(textarea);

}

el.addEventListener('click',el.handler);

},

componentUpdated(el,{value}){

el.$value=value;

},

//指令與元素解綁的時(shí)候,移除事件綁定

unbind(el){

el.removeEventListener('click',el.handler);

}

export default vCopy

2.到這里,一鍵Copy的功能就實(shí)現(xiàn)了,最后再說(shuō)一嘴怎么將自定義指令注冊(cè)到全局:再新建一個(gè)js(directives.js)文件文件來(lái)注冊(cè)所有的全局指令。

import copy from './v-copy';

//自定義指令

const directives={

copy,

}

//這種寫(xiě)法可以批量注冊(cè)指令

export default{

install(Vue){

Object.keys(directives).forEach(key)=>{

Vue.directive(lkey,directives[key]);

});

};

}

3.最后,在main.js中這樣引入:

important Vue from 'vue';

important Directives from"./directives";

Vue.use(Directives);

按鈕級(jí)別權(quán)限控制

權(quán)限控制分為頁(yè)面級(jí)別和按鈕級(jí)別,這兩種思路基本是一致的。

頁(yè)面級(jí)別:用戶(hù)登錄后,獲取用戶(hù)role,將role和路由表每個(gè)頁(yè)面的需要的權(quán)限作比較,生成最終用戶(hù)可訪(fǎng)問(wèn)的路由表。最后通過(guò)router.addRoutes動(dòng)態(tài)掛載?,F(xiàn)在是通過(guò)獲取到用戶(hù)的role之后,在前端用v-if手動(dòng)判斷來(lái)區(qū)分不同權(quán)限對(duì)應(yīng)的按鈕的。。

按鈕級(jí)別:用戶(hù)登錄后,獲取用戶(hù)role,在前端用v-if或者封裝一個(gè)自定義指令,手動(dòng)判斷來(lái)區(qū)分不同權(quán)限對(duì)應(yīng)的按鈕的思路:

登錄:當(dāng)用戶(hù)填寫(xiě)賬號(hào)和密碼后向服務(wù)器驗(yàn)證是否正確,驗(yàn)證通過(guò)之后,服務(wù)端回返回一個(gè)token,拿到token之后(將token存在sessionStorage中,保證刷新新頁(yè)面后能記住用戶(hù)登錄狀態(tài)),前端會(huì)根據(jù)token再去拉取一個(gè)user_info的接口來(lái)獲取用戶(hù)的詳細(xì)信息(如用戶(hù)角色,用戶(hù)權(quán)限,用戶(hù)名等等信息)。

權(quán)限驗(yàn)證:通過(guò)token獲取用戶(hù)對(duì)應(yīng)的role,自定義指令,獲取路由meta屬性里btnPermissions(注:meta.btnPermissions是存放按鈕權(quán)限的數(shù)組,在路由表里配置),然后判斷role是否在btnPermission數(shù)組里,若不再即刪除該按鈕DOM。

路由配置:

path:'/permission',

component:Layout,

name:'權(quán)限測(cè)試',

meta:{btnPermissions:['admin','super','normal']},//頁(yè)面需要的權(quán)限

children:[

{

?path:'supper',

component:_import('system/supper'),

name:'權(quán)限測(cè)試頁(yè)',

meta:{btnPermissions:['admin','supper']}//頁(yè)面需要權(quán)限,

},

{

path:'normal',

component:_import('system/normal'),

name:'權(quán)限測(cè)試頁(yè)',

meta:{btnPermissions:['admin']}//頁(yè)面需要的權(quán)限

}]

import Vue from "vue"

const has=Vue.directive('has',{

bind:function(el,binding,vnode){

let btnPermissionArr=vnode.context.$route.meta.btnPermissions;

if(!Vue.prototype.$_has(btnPermissionArr)){

el.parantNode.removeChild(el);

}

}

})

Vue.prototype.$_has=function(value){

let isExist=false;

//獲取用戶(hù)按鈕權(quán)限

let btnPermissionStr=sessionStorage.getItem("btnPermissions");

if(btnPermissionStr==undefined||btnPermissionStr==null){

return false;

}

if(value.indexOf(btnPermissionsStr)>-1){

isExist=true;

}

return isExist;

};

export {has}

然后在main.js文件引入文件

important has from "./public/js/btnPermissions.js";

頁(yè)面中按鈕只需加v-has即可

<el-button @click="editClick" type="primary" v-has>編輯</el-button>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容