Vue.js 前端开发 快速入门与专业应用
上QQ阅读APP看书,第一时间看更新

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中取消了这个特性,推荐使用组件来实现需要的业务。