【vue筆記2】-自定義指令
阿新 • • 發佈:2018-12-19
基礎
除了內建指令,Vue.js也允許註冊自定義指令。自定義指令提供一種機制將資料的變化對映為DOM行為。 Vue.js用Vue.directive(id,definition)方法註冊一個全域性自定義指令,它接受兩個引數:指令ID與定義物件。也可以用元件的directives選項註冊一個區域性自定義指令(此方法相當於AngularJS restrict)屬性值為A。
- 鉤子函式 bind——只調用一次,在指令第一次繫結到元素上時呼叫。 update——在bind之後立即以初始值為引數第一次呼叫,之後每當繫結值變化時呼叫,引數為新值與舊值。 unbind——只調用一次,在指令從元素上解綁時呼叫。
Vue.directive('my-directive',{
bind:function(){
//準備工作
//例如,新增事件處理器或只需要執行一次的高耗任務
},
update:function(){
//值更新時的工作
//也會以初始值為引數呼叫一次
},
unbind:function(){
//清理工作
//例如,刪除bind()新增的事件監聽器
}
})
在註冊之後,便可以在Vue.js模板中這樣用(記著新增字首-v):
<div v-my-directive="someValue"></div>
當值需要update函式時,可以傳入一個函式替代定義物件:\
Vue.directive('my-directive',function(value){
//這個函式用作update()
})
- 指令例項屬性 所有的鉤子函式都將被複制到實際的指令物件中,在鉤子內this指向這個指令物件。這個物件暴露了一些有用的屬性: el——指令繫結的元素。 vm——擁有該指令的上下文ViewModel. expression——指令的表示式,不包括引數和過濾器。 arg——指令的引數。 name——指令的名字,不包括字首。 modifiers——一個物件,包括指令的修飾符。 descriptor——一個物件,包括指令的解析結果。 注:我們應當將這些屬性視為只讀,不要修改它們。我們也可以給指令物件新增自定義屬性,但是注意不要覆蓋已有的內部屬性。程式碼示例如下:
<body id="example" @click=up">
<div id="demo" v-demo:hello.a.b="msg"></div>
</body>
<sciprt>
Vue.directive('demo',{
bind:function(){
console.log('demo bound');
},
update:function(value){
this.el.innerHTML =
'name-'+this.name+'</br>'+
'expression-'+this.expression+'</br>'+
'argument-'+this.arg+'</br>'+
'modifiers-'+JSON.stringify(this.modifiers)+'</br>'+
'value-'+this.value+'</br>'+
'vm-msg-'+this.vm.msg+'</br>'+
</script>
var demo = new Vue({
el:'#example',
data:{
msg:'hello!'
},
methods:{
up:function(){
console.info('click');
}
}
}):
指令輸出結果: name-demo expression-msg argument-hello modifiers-{“b”:true,“a”:true} value-hello! vm-msghello!
- 物件字面量 如果指令需要多個值,則可以傳入一個JavaScript物件字面量。記住,指令可以使用任意合法的JavaScript表示式。程式碼示例如下:
<body>
<div id="demo" v-demo="{color:'white',text:'hello'}"></div>
</body>
<script>
Vue.directive('demo',function(value){
console.log(value.color) //white
console.log(value.text) //hello!
})
var demo = new Vue({
el:'#demo'
})
</script>
輸出結果: white hello!
- 字面修飾符
當指令使用了字面修飾符時,它的值將按普通字串處理並傳遞給update方法。update方法將只調用一次,因為普通字串不能響應資料變化。程式碼示例如下:
<body>
<div id="demo" v-demo.literal="foo bar baz"></div>
</body>
<script>
Vue.directive('demo',function(value){
console.log(value)
})
var demo = new Vue({
el:'#demo'
})
</script>
foo bar baz
- 元素指令 有時我們想以自定義元素的形式使用指令,而不是以屬性的形式。這與AngularJS的E指令非常相似。元素指令可以看做是一個輕量元件。可以像下面這樣註冊一個自定義元素指令:
<body id="demo">
<my-directive class="hello" name="hi"></my-directive>
</body>
<script>
Vue.elementDiective('my-directive',{
//API同普通指令
bind:function(){
console.log(this.el.className)
console.log(this.el.getAttribute("name"))
}
})
var demo = new Vue({
el:'#demo'
})
</script>
元素指令不能接受引數或表示式,但是它可以讀取元素的特性,從而決定它的行為。 不同於普通指令,元素指令是終結性的。這意味著,一旦Vue遇到一個元素指令,它將跳過該元素及其子元素。
高階選項
Vue允許註冊自定義指令。自定義指令提供一種機制將資料的變化對映為DOM行為。
- params 自定義指令可以接受一個params陣列,指定一個特性列表,Vue編譯器將自動提取繫結元素的這些特性。程式碼例項如下:
<body id="demo">
<my-directive class="hello" name="hi" a="params"></my-directive>
</body>
<script>
Vue.elementDirective('my-directive',{
params:['a'],
//API同普通指令
bind:function(){
console.log(this.params.a);
console..log(this.el.getAttribute("name"));
}
})
var demo = new Vue({
el:'#demo'
})
<script>
此API也支援動態屬性。this.params[key]會自動保持更新。另外,可以指定一個回撥,在值變化的時候,程式碼如下:
<body id="demo">
<my-directive class="hello" name="hi" a="params"></my-directive>
</body>
<script>
Vue.elementDirective('my-directive',{
params:['a'],
paramWatchers:{
a:function(val,oldVal){
console.log('a changed!')
}
}
})
var demo = new Vue({
el:'#demo',
data:{
someValue:'value'
}
})
<script>
- deep 如果自定義指令使用在一個物件上,當物件內部屬性變化時要觸發update,則在指令定義物件中指定deep:true
- twoWay 如果指令想向Vue例項寫回資料,則在指令定義物件中指定twoWay:true。該選項允許在指令中使用this.set(value)。程式碼示例如下:
<body id="demo">
自定義元件:<input v-example="a.b.c"/><br/>
父作用域:{a.b.c}
</body>
<script>
Vue.directive('example',{
twoWay:true,
bind:function(){
this.handler = function(){
//把資料寫回vm
//如果指令這樣繫結v-example="a.b.c"
//這裡將會給vm.a.b.c賦值
this.set(this.el.value);
}.bind(this)
this.el.addEventListener('input',this.handler);
}
})
var demo = new Vue({
el:'#demo',
data:{
a:{b:{c:2}}
}
})
</script>
- acceptStatement 傳入acceptStatement:true可以讓自定義指令接受內聯語句,就像v-on那樣。程式碼示例如下:
<body id="demo">
<div v-my-directive="a++"></div>
{{a}}
</body>
<script>
Vue.directive('my-directive',{
acceptStatement:true
update:function(fn){
//傳入值是一個函式
//在呼叫它時將在所屬例項作用域內計算“a++”語句
console.info(fn.toString());
fn();
}
})
var demo = new Vue({
el:'#demo',
data:{
a:5
}
})
</script>
- Terminal(1.0.19及以後版本) Vue 通過遞迴遍歷DOM樹來編譯模組,但是當它遇到terminal指令時會停止遍歷這個元素的後代,這個指令將接管編譯這個元素及其後代元素的任務。v-if和v-for都是terminal指令。 編寫自定義terminal指令是一個高階話題,需要較好的理解Vue的程式設計流程,但並不是說不可能編寫自定義的terminal指令。用terminal:true指定自定義terminal指令,可能還需要用Vue.FragmentFactory來編譯partial。下面是一個自定義的terminal指令,它編譯其內容模板並將結果注入到頁面的另一個地方。
- priority 可以給指令指定一個優先順序。如果沒有指定優先順序,普通指令預設是1000,terminal指令預設是2000。同一個元素上優先順序高的指令會比其他指令處理得早一些,優先順序一樣的指令按照它在元素特性列表中出現的順序依次處理,但是不能保證這個順序在不同的瀏覽器中是一致的。 另外,流程控制指令v-if和v-for在編譯過程中始終擁有最高的優先順序。