寫(xiě)在文本前:相信在做vue的項(xiàng)目,你肯定接觸了指令,我們常用vue內(nèi)置的一些指令,比如v-model,v-text,v-if,v-show等等,但是這些內(nèi)置指令不在本文的講解范疇,本文想說(shuō)的是其自定義指令。思考一下,自定義指令我們用在哪里?是不是一下子想不出來(lái),感覺(jué)做一般的項(xiàng)目很少用到指令呢,想不到指令用在哪?。∫?yàn)槲覀兊拇_很少用,但不是說(shuō)不會(huì)用??垂俜絘pi文檔里有這么一句話:普通 DOM 元素進(jìn)行底層操作,這時(shí)候就會(huì)用到自定義指令。也就是說(shuō)我們?cè)诓僮髌胀―OM的時(shí)候有可能會(huì)用到。在做項(xiàng)目的時(shí)候,我們有很多種方法來(lái)替代自定義指令,所以讓我們忽略了vue自定義指令的用處。下邊我們一步步來(lái)了解vue自定義指令。
舉幾個(gè)栗子
(1、輸入框焦點(diǎn)自動(dòng)觸發(fā)。
(1、輸入框的電話號(hào)碼,郵箱,身份證號(hào)碼等的校驗(yàn)。
上面這幾個(gè)場(chǎng)合,我們?cè)谧鲰?xiàng)目的時(shí)候完全可以用其他方法代替,但是vue自定義指令能讓我們做到一勞永逸,做到一處定義,全局調(diào)用。使其代碼簡(jiǎn)潔高效,維護(hù)方便。接下來(lái),我們會(huì)一步步深入vue自定義指令。
1、首先看下官方介紹,如下:
/* 自定義指 */
import Vue from 'vue'
/**
* 模板
* v-lang
* 五個(gè)注冊(cè)指令的鉤子函數(shù)
*/
Vue.directive('mydirective', {
/**
* 1.被綁定
* 做綁定的準(zhǔn)備工作
* 比如添加事件監(jiān)聽(tīng)器,或是其他只需要執(zhí)行一次的復(fù)雜操作
*/
bind: function(el, binding, vnode) {
console.log('1 - bind');
},
// 2.綁定到節(jié)點(diǎn)
inserted: function(el, binding, vnode) {
console.log('2 - inserted');
},
/**
* 3.組件更新
* 根據(jù)獲得的新值執(zhí)行對(duì)應(yīng)的更新
* 對(duì)于初始值也會(huì)調(diào)用一次
*/
update: function(el, binding, vnode, oldVnode) {
console.log('3 - update');
},
// 4.組件更新完成
componentUpdated: function(el, binding, vnode, oldVnode) {
console.log('4 - componentUpdated');
},
/**
* 5.解綁
* 做清理操作
* 比如移除bind時(shí)綁定的事件監(jiān)聽(tīng)器
*/
unbind: function(el, binding, vnode) {
console.log('5 - bind');
}
})
/**
鉤子函數(shù)
1、bind:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用,用這個(gè)鉤子函數(shù)可以定義一個(gè)綁定時(shí)執(zhí)行一次的初始化動(dòng)作。
2、inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用,不必存在于document中)。
3、update:被綁定于元素所在的模板更新時(shí)調(diào)用,而無(wú)論綁定值是否變化。通過(guò)比較更新前后的綁定值,可以忽略不必要的模板更新。
4、componentUpdated:被綁定元素所在模板完成一次更新周期時(shí)調(diào)用。
5、unbind:只調(diào)用一次,指令與元素解綁時(shí)調(diào)用。
*/
執(zhí)行順序:
頁(yè)面加載時(shí)
bind
inserted
組件更新時(shí)
update
componentUpdated
卸載組件時(shí)
unbind
官方地址請(qǐng)移步至,directive,上面只是做了個(gè)簡(jiǎn)單的說(shuō)明,接下來(lái)我們?cè)敿?xì)的介紹vue自定義指令的各個(gè)鉤子函數(shù)到底如何觸發(fā)。
2、鉤子函數(shù)簡(jiǎn)單講解
就個(gè)人而言, bind和update也許是這五個(gè)里面最有用的兩個(gè)鉤子了.這個(gè)也是我們下邊主要要說(shuō)的2個(gè)鉤子函數(shù)。其它函數(shù)不常用,我也沒(méi)搞明白。
(1)鉤子函數(shù) bind
bind:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用。在這里可以進(jìn)行一次性的初始化設(shè)置。
<input id="input1" v-mydirective> // html元素
Vue.directive('mydirective', {
bind: function(el, binding, vnode) {
el.style.border = "1px solid red"
}
}
上面代碼的效果就是輸入框的邊框變成了1像素的紅色。當(dāng)然你也可以設(shè)置其它試試。
<input id="input1" v-mydirective> // html元素
Vue.directive('mydirective', {
bind: function(el, binding, vnode) {
el.addEventListener('click', function (event) {
alert('hellow world')
})
}
}
在bind鉤子函數(shù)里,我們可以添加一些事件,在其某種條件下觸發(fā)(比如點(diǎn)擊事件,鍵盤(pán)事件),如上代碼,點(diǎn)擊input輸入框就會(huì)彈出 “hellow world”。至于bind里面的參數(shù)的含義,建議自己動(dòng)手輸入出來(lái)看看。很簡(jiǎn)單是吧,下邊我們來(lái)些稍微復(fù)雜一點(diǎn)的。看如下代碼:
指令鉤子函數(shù)會(huì)被傳入以下參數(shù):
/**
鉤子函數(shù)的參數(shù):(el, binding, vnode, oldVnode)
el:指令所綁定的元素,可以用來(lái)直接操作 DOM 。
binding:一個(gè)對(duì)象,包含以下屬性
name:指令名,不包含v-的前綴;
value:指令的綁定值;例如:v-my-directive="1+1",value的值是2;
oldValue:指令綁定的前一個(gè)值,僅在update和componentUpdated鉤子函數(shù)中可用,無(wú)論值是否改變都可用;
expression:綁定值的字符串形式;例如:v-my-directive="1+1",expression的值是'1+1';
arg:傳給指令的參數(shù);例如:v-my-directive:foo,arg的值為 'foo';
modifiers:一個(gè)包含修飾符的對(duì)象;例如:v-my-directive.a.b,modifiers的值為{'a':true,'b':true}
vnode:Vue編譯的生成虛擬節(jié)點(diǎn);
oldVnode:上一次的虛擬節(jié)點(diǎn),僅在update和componentUpdated鉤子函數(shù)中可用。
*/
這里我們著重注意一下,binding對(duì)象下的value,oldValue,arg,expression,modifiers這幾個(gè)屬性,根據(jù)這幾個(gè)屬性,我們可以做到更強(qiáng)大的自定義指令,下邊我們參考案例來(lái)說(shuō):
<div v-mydirective:left="100" id=”box"></div> // html元素
Vue.directive('mydirective', {
bind: function(el, binding, vnode) {
el.style.position = 'fixed';
const s = (binding.arg === 'left' ? 'left' : 'top');
el.style[s] = binding.value + 'px';
}
}
上面的代碼是使id=”box“的這個(gè)div元素絕對(duì)定位了,而且設(shè)置了left的值為100px;
(2)鉤子函數(shù) update
update:每當(dāng)元素本身更新(但是子元素還未更新)時(shí)觸發(fā)。這句話怎么理解呢?我們用案例來(lái)說(shuō)明,如下:
<template>
<div id="box">
<input v-model="myname" v-mydirective/>
</div>
<template>
export default {
data(){
return{
myname:"zhangshan"
}
},
directives:{
'mydirective':{
update: function(el, binding, vnode, oldVnode) {
console.log('update更新了');
}
}
}
}
上邊代碼,輸入框默認(rèn)值是"zhangshan",如果我們修改了myname值,那么就會(huì)觸發(fā)update函數(shù)的執(zhí)行,輸出“update更新了”
再來(lái)個(gè)復(fù)雜一點(diǎn)的案例如下:
<template>
<div id="box">
<input type="text" v-model="myname" v-mydirective="{type:'name',val:myname}"/>
<input type="text" v-model="myemail" v-mydirective="{type:'email',val:myemail}"/>
</div>
<template>
export default {
data(){
return{
myname:"zhangshan",
myemail:'***@163.com'
}
},
directives:{
'mydirective':{
update: function(el, binding, vnode, oldVnode) {
//update:指令的值可能發(fā)生了改變,也可能沒(méi)有。但是你可以通過(guò)比較更新前后的值來(lái)忽略不必要的模板更新
if(binding.oldValue.val != binding.value.val){// 進(jìn)行判斷,避免同時(shí)觸發(fā)多個(gè)判斷
let checkStatus = true;// 定義驗(yàn)證狀態(tài) 局部變量
if(binding.value.type == 'name'){
if(binding.value.val.length>5){
checkStatus = false;
console.log("輸入的姓名長(zhǎng)度大于5了")
}
}
if(binding.value.type == 'email'){// 驗(yàn)證郵箱
if(!/^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a- z0-9]+$/g.test(binding.value.val)){
checkStatus = false;
}
}
if(checkStatus){
el.style.border = "1px solid #333";//驗(yàn)證通過(guò)input邊框顏色就變成#333
}else{
el.style.border = "1px solid red";//驗(yàn)證不通過(guò)input邊框顏色就變成紅色
}
}
}
}
}
}
上邊的案例,我們通過(guò)bind下的modifiers屬性實(shí)現(xiàn)。modifiers:一個(gè)包含修飾符的對(duì)象;例如:v-my-directive.a.b,modifiers的值為{'a':true,'b':true}。這樣我們?cè)趗pdate鉤子函數(shù)里根據(jù)所傳入的type類型做判斷來(lái)執(zhí)行哪個(gè)驗(yàn)證方法。
(3)鉤子函數(shù) inserted
inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用(父節(jié)點(diǎn)存在即可調(diào)用,不必存在于document中)。
<input id="input1" v-mydirective> // html元素
Vue.directive('mydirective', {
inserted: function(el, binding, vnode) {
el.focus()//輸入框自動(dòng)獲取焦點(diǎn)
}
}
對(duì)于鉤子函數(shù) inserted,我也是一知半解,所用的不多,但是有個(gè)常用的方法是寫(xiě)在這里面的,就是輸入框自動(dòng)獲取焦點(diǎn),也就是上面的代碼。
(4)鉤子函數(shù) bind和鉤子函數(shù) inserted的區(qū)別。
據(jù)文檔所說(shuō),插入父節(jié)點(diǎn)時(shí)調(diào)用 inserted,來(lái)個(gè)測(cè)試。
bind: function (el) {
console.log(el.parentNode) // null
console.log('bind')
},
inserted: function (el) {
console.log(el.parentNode) // <div id="login">...</div>這個(gè)元素是指令所在元素的父元素,具體根據(jù)自己的寫(xiě)法不同
console.log('inserted')
}
分別在兩個(gè)鉤子函數(shù)中輸出父節(jié)點(diǎn):bind 時(shí)父節(jié)點(diǎn)為 null,inserted 時(shí)父節(jié)點(diǎn)存在。
(5)鉤子函數(shù) componentUpdated和鉤子函數(shù) unbind
// 4.組件更新完成
componentUpdated: function(el, binding, vnode, oldVnode) {
console.log('4 - componentUpdated')
},
/*** 5.解綁
* 做清理操作
* 比如移除bind時(shí)綁定的事件監(jiān)聽(tīng)器
*/
unbind: function(el, binding, vnode) {
console.log('5 - bind');
}
對(duì)于這2個(gè)鉤子函數(shù),沒(méi)有做太多的研究,unbind可能會(huì)用到,用于釋放實(shí)例資源占用等操作。
關(guān)于vue.js指令大致也就說(shuō)這么多吧,如果錯(cuò)誤,歡迎指正拍磚......