本文承接上文,繼續(xù)對Vue的指令進(jìn)行介紹,同時也是指令系列的終章。建議讀者先閱讀上篇文章卦方,以免有不解之處。前文請參考“Vue學(xué)習(xí)——指令(三)”
自定義指令
前文已經(jīng)介紹了Vue所有的內(nèi)置指令泰佳,這些指令可以滿足大多數(shù)業(yè)務(wù)需求盼砍,然而,在某些特殊情況下逝她,我們希望可以對普通的DOM元素進(jìn)行底層操作浇坐,這時我們就需要用到自定義指令了。
自定義指令的注冊
自定義指令需要注冊后才能使用汽绢,Vue提供了兩種注冊方式:全局注冊和局部注冊吗跋。全局注冊使用Vue.directive()方法來注冊一個全局自定義指令,該方法接收兩個參數(shù)宁昭,第一個參數(shù)是指令的ID跌宛;第二個參數(shù)是一個定義對象或者函數(shù)對象,指令要實現(xiàn)的功能在這個對象中定義积仗。
語法形式如下:
Vue.directive(id, [definition])
例如疆拘,要編寫一個讓元素自動獲取焦點的全局指令,代碼示例如下:
Vue.directive('focus', {...})
全局指令可以在任何Vue實例的模版中使用,代碼示例如下:
<div id="app">
<input v-focus>
</div>
<div id="app2">
<input v-focus>
</div>
<script>
Vue.directive('focus', {
// ...
})
new Vue({
el: '#app'
})
new Vue({
el: '#app2'
})
</script>
v-focus是一個全局自定義指令寂曹,因此可以在任何Vue實例的模版中使用哎迄。
局部注冊是在Vue實例的選項對象中使用directives選項進(jìn)行注冊,代碼示例如下:
new Vue({
el: '#app',
directives: {
// 注冊一個局部的自定義指令
focus: {
// ...
}
}
})
- 局部注冊的自定義指令只能在該實例綁定的視圖中使隆圆。
看下面的示例:
<div id="app">
<input v-focus>
</div>
<div id="app2">
<input v-focus>
</div>
<script>
new Vue({
el: '#app'
directives: {
// 注冊一個局部的自定義指令
focus: {
// ...
}
}
})
new Vue({
el: '#app2'
})
</script>
在瀏覽器打開該頁面時漱挚,Vue會給出一個警告信息:[Vue warn]: Failed to resolve directive: focus
鉤子函數(shù)
自定義指令的功能是在定義對象中實現(xiàn)的,而定義對象則是由鉤子函數(shù)組成的渺氧,Vue提供了下面幾個鉤子函數(shù)旨涝,這些鉤子函數(shù)都是可選的。
- bind: 只調(diào)用一次侣背,指令第一次綁定到元素時調(diào)用白华。指令如果需要一些一次性的初始化設(shè)置,可以放到這個鉤子函數(shù)中贩耐。
- inserted: 被綁定元素插入父節(jié)點時調(diào)用(父節(jié)點存在即可調(diào)用弧腥,不必存在于document對象中)
- update: 所在組件的VNode更新時調(diào)用(無論指令的值是否發(fā)生了變化),但是可能發(fā)生在其子VNode更新之前潮太」芴拢可以通過比較更新前后的值來忽略不必要的模版更新。
- componentUpdated: 指令所在組件的VNode及其子VNode全部更新后調(diào)用。
- unbind: 只調(diào)用一次抛蚤,指令與元素解綁時調(diào)用台谢。
根據(jù)指令要實現(xiàn)功能的不同寻狂,選擇相應(yīng)的鉤子函數(shù)來編寫代碼岁经。
例:在元素插入父節(jié)點時自動獲得焦點,代碼示例如下:
<div id="app">
<input v-focus>
</div>
<script>
// 注冊一個全局自定義指令
Vue.directive('focus', {
// 當(dāng)綁定元素插入父節(jié)點時
inserted: function(el) {
el.focus()
}
})
new Vue({
el: '#app'
})
</script>
指令的鉤子函數(shù)可以帶有一些參數(shù)蛇券,例如上述代碼中的el參數(shù)缀壤,具體的參數(shù)列表如下所示:
- el:指令所綁定的元素,可以用來直接操作DOM纠亚。
- binding:一個對象塘慕,包括以下屬性:
- name:指令名,不包括v-前綴蒂胞。
- value:指令的綁定值图呢。
- oldValue:指令綁定的前一個值,僅在update和componentUpdated鉤子中可用骗随。無論值是否改變都可用蛤织。
- expression:字符串形式的指令表達(dá)式。
- arg:傳給指令的參數(shù)鸿染,可選指蚜。
- modifiers:一個包含修飾符的對象。
- vonde:Vue編譯生成的虛擬節(jié)點涨椒。
- oldVonde:上一個虛擬節(jié)點摊鸡,僅在update和componentUpdated鉤子中可用。
要注意的是蚕冬,除了el參數(shù)外免猾,其他參數(shù)都應(yīng)該時只讀的,切勿進(jìn)行修改囤热。
下面編寫一個自定義指令猎提,在其鉤子函數(shù)中將各個參數(shù)輸出,代碼示例如下:
<div id="app" v-demo:foo.a.b="message"></div>
<script>
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>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(',')
}
})
new Vue({
el: '#app',
data: {
message: 'Hello'
}
})
</script>
我們將bind鉤子函數(shù)的所有參數(shù)信息取出來拼接成字符串赢乓,賦值給<div>元素的innerHTML屬性忧侧。渲染結(jié)果如下:
name: "demo"
value: "Hello"
expression: "message"
argument: "foo"
modifiers: {"a": true, "b": true}
vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, ra, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder
動態(tài)指令參數(shù)
在之前的文章中已經(jīng)介紹過,指令的參數(shù)可以是動態(tài)參數(shù)牌芋,同樣地蚓炬,自定義的指令也可以使用動態(tài)參數(shù)。
例:我們想讓某個元素固定在頁面中的某個位置躺屁,在出現(xiàn)滾動條時肯夏,元素也不會隨著滾動。這可以通過設(shè)置CSS樣式屬性position為fixed來實現(xiàn),同時使用top驯击、right烁兰、botton、left等屬性以窗口為參考點來進(jìn)行定位徊都。下面通過自定義指令來實現(xiàn)這個功能沪斟。代碼示例如下:
<div id="app">
<!-- 直接給出指令的參數(shù) -->
<p v-pin:top="100">
Vue學(xué)習(xí)
</p>
<!-- 使用動態(tài)參數(shù) -->
<p v-pin:[direction]="100">
Vue學(xué)習(xí)
</p>
</div>
<script>
Vue.directive('pin', {
bind: function(el, binding, vnode) {
el.style.position = 'fixed';
let s = binding.arg || 'left';
el.style[s] = binding.value + 'px'
}
})
new Vue({
el: '#app',
data: {
direction: 'left'
}
})
</script>
函數(shù)簡寫
如果自定義指令在bind和update鉤子函數(shù)中的行為一致,且只需要用到這兩個鉤子函數(shù)暇矫,那么可以在注冊時傳遞一個函數(shù)對象作為參數(shù)主之。
代碼示例如下:
Vue.directive('color-swatch', function(el, binding) {
el.style.backgroundColor = binding.value
})
對象字面量
如果指令需要多個值,可以傳入一個JavaScript對象字面量李根。要記住的是槽奕,指令可以接收所有合法的JavaScript表達(dá)式。
<div v-demo="{color: 'white', text: 'hello'}"></div>
<!-- 省略非關(guān)鍵代碼 -->
Vue.directive('demo', function(el, binding) {
console.log(binding.value.color)
console.log(binding.value.text)
})
以上便是Vue指令這一系列的全部內(nèi)容房轿,應(yīng)該說最常用的指令就是v-if粤攒、v-for、v-on囱持、v-bind和v-model夯接,只要熟練掌握這五個指令的用法即可完成大部分工作。
此外洪唐,在指令系列還介紹了自定義指令的開發(fā)钻蹬。需要注意的是,自定義指令只應(yīng)該用于封裝對DOM的操作凭需,不要將其用作別的用途问欠。在某些特殊需求下,通過自定義指令來封裝DOM操作粒蜈,可以簡化代碼的編寫顺献,提高代碼的重用型。
在下篇文章中枯怖,打算寫幾個實際場景中用得到的示例注整,敬請期待!