3.2 自定义指令基础
除了内置指令外,Vue.js也提供了方法让我们可以注册自定义指令,以便封装对DOM元素的重的处理行为,提高代码复用率。本小节主要说明了如何创建、注册自定义指令,以及讲述指令的相关属性钩子函数,更深一步地了解指令在Vue.js中起到的作用。
3.2.1 指令的注册
我们可以通过Vue.directive(id, definition) 方法注册一个全局自定义指令,接收参数id和定义对象。id是指令的唯一标识,定义对象则是指令的相关属性及钩子函数。例如:
Vue.directive(‘global-directive', definition); // 我们暂时只注册了这个指令,并没有赋予这个指令任何功能。
我们可以在模板中这么使用:
<div v-global-directive></div>
而除了全局注册指令外,我们也可以通过在组件的directives选项注册一个局部的自定义指令。例如:
var comp = Vue.extend({ directives : { 'localDirective' : {} // 可以采用驼峰式命名 } });
该指令就只能在当前组件内通过v-local-directive的方式调用,而无法被其他组件调用。
3.2.2 指令的定义对象
我们在注册指令的同时,可以传入definition定义对象,对指令赋予一些特殊的功能。这个定义对象主要包含三个钩子函数:bind、 update和unbind。
bind:只被调用一次,在指令第一次绑定到元素上时调用。
update:指令在bind之后以初始值为参数进行第一次调用,之后每次当绑定值发生变化时调用,update接收到的参数为newValue和oldValue
unbind:指令从元素上解绑时调用,只调用一次。
这三个函数都是可选函数,但注册一个空指令肯定没有意义,来看下面这个例子,会使我们对整个指令周期有更明确的认识。
<div v-if="isExist" v-my-directive="param"></div> Vue.directive('my-directive', { bind : function() { console.log('bind', arguments); }, update : function(newValue, oldValue) { console.log('update', newValue, oldValue) }, unbind : function() { console.log('unbind', arguments); } }) var vm = new Vue({ el : '#app', data : { param : 'first', isExist : true } });
我们在控制台里先后输入vm.param ='second’和vm.isExist = false,整体输出如下:
另外,如果我们只需要使用update函数时,可以直接传入一个函数代替定义对象:
Vue.directive('my-directive', function(value) { // 该函数即为update函数 });
上述例子中,可以使用my-directive指令绑定的值是data中的param属性。也可以直接绑定字符串常量,或使用字面修饰符,但这样的话需要注意update方法将只调用一次,因为普通字符串不能响应数据变化。例如:
<div v-my-directive="constant string"/></div> // -> value为undefined,因 为data中没有对应的属性 <div v-my-direcitve="'constant string'"></div> // -> value 为constant string,绑定字符串需要加单引号 <div v-my-directive.literal="constant string"></div> // -> value为constant string,利用字面修饰符后无需使用单引号
除了字符串外,指令也能接受对象字面量或任意合法的JavaScript表达式。例如:
<div v-my-directive="{ title : 'Vue.js', author : 'You'}" ></div> <div v-my-directive="isExist ? 'yes' : 'no'" ></div>
注意此时对象字面量不需要用单引号括起来,这和字符串常量不一样。
3.2.3 指令实例属性
除了了解指令的生命周期外,还需要知道指令中能调用的相关属性,以便我们对相关DOM进行操作。在指令的钩子函数内,可以通过this来调用指令实例。下面就详细说明指令的实例属性。
el:指令绑定的元素。
vm:该指令的上下文ViewModel,可以为new Vue()的实例,也可以为组件实例。
expression:指令的表达式,不包括参数和过滤器。
arg:指令的参数。
name:指令的名字,不包括v-前缀。
modifiers:一个对象,包含指令的修饰符。
descriptor:一个对象,包含指令的解析结果。
我们可以通过以下这个例子,更直观地了解到这些属性:
<div v-my-msg:console.log="content"></div> Vue.directive('my-msg', { bind : function() { console.log('~~~~~~~~~~~bind~~~~~~~~~~~~~'); console.log('el', this.el); console.log('name', this.name); console.log('vm', this.vm); console.log('expression', this.expression); console.log('arg', this.arg); console.log('modifiers', this.modifiers); console.log('descriptor', this.descriptor); }, update : function(newValue, oldValue) { var keys = Object.keys(this.modifiers); window[this.arg][keys[0]](newValue); }, unbind : function() { } }); var vm = new Vue({ el : '#app', data : { content : 'there is the content' } });
输出结果如下:
3.2.4 元素指令
元素指令是Vue.js的一种特殊指令,普通指令需要绑定在某个具体的DOM元素上,但元素指令可以单独存在,从使用方式上看更像是一个组件,但本身内部的实例属性和钩子函数是和指令一致的。例如:
<div v-my-directive></div> // -> 普通指令使用方式 <my-directive></my-directive> // -> 元素指令使用方式
元素指令的注册方式和普通指令类似,也有全局注册和局部注册两种。
Vue.elementDirective('my-ele-directive') // 全局注册方式 var Comp = Vue.extend({ // 局部注册,仅限该组件内使用 … // 省略了其他参数 elementDirectives : { 'eleDirective' : {} } }); Vue.component('comp', Comp);
元素指令不能接受参数或表达式,但可以读取元素特性从而决定行为。而且当编译过程中遇到一个元素指令时,Vue.js将忽略该元素及其子元素,只有元素指令本身才可以操作该元素及其子元素。
Vue.js 2.0中取消了这个特性,推荐使用组件来实现需要的业务。