Vue(九) 自定义指令

前面介绍了许多 Vue 内置的指令,比如 v-if、v-show等,这些丰富的指令能满足我们绝大部分的业务需求,不过在需要一些特殊功能时,我们仍然希望对 DOM 进行底层的操作,这时就要用到自定义指令。

基本用法

自定义指令的注册方法和组件很像,也分全局注册和局部注册,比如注册一个 v-focus 的指令,用于在 <input>、<textarea> 元素初始化时自动获取焦点,两种写法分别是:

//全局注册
Vue.directive('focus', {
    //指令选项
});
// 局部注册
var app = new Vue({
    el: '#app',
    directives: {
        focus: {
           	//指令选项
        }
    }
})

上面只是注册了自定义指令 v-focus,还没有实现具体功能,下面具体介绍自定义指令的各个选项。

自定义指令的选项是由几个钩子函数组成的,每个都是可选的。

  • bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时只执行一次的初始化操作。
  • inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  • update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值可以忽略不必要的模板更新。
  • componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
  • unbind:只调用一次,指令与元素解绑时调用。

可以根据需求在不同的钩子函数内完成逻辑代码,例如上面的 v-focus,我们希望在元素插入父节点时就调用,那用到的最好是 inserted。例如:

<div id="app">
        <input type="text" v-focus>
    </div>
    <script>
        Vue.directive('focus', {
            inserted: function (el) {
                el.focus();
            }
        })

        var app = new Vue({
            el: '#app'
        })
    </script>

每个钩子函数都有几个参数可选,比如上面我们用到了 el。它们的含义如下:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下属性:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如 v-my-directive=“1 + 1”,value 的值是2。
    • oldValue:指令绑定的前一个值,仅在 update 和 componentupdated 钩子中可用。无论值是否改变都可以。
    • expression:绑定值的字符串形式,例如 v-my-directive=“1 + 1”,expression 的值是“1 + 1”。
    • arg:传给指令的参数。例如 v-my-directive: foo,arg 的值是 foo。
    • modifiers:一个包含修饰符的对象。例如 v-my-directive.foo.bar,修饰符对象 modifiers 的值是 { foo: true, bar: true }。
  • vnode:Vue编译生成的虚拟节点,在进阶中介绍。
  • oldVnode:上一个虚拟节点仅在 update 和 componentupdated 钩子中可用。

下面是结合了以上参数的一个具体样例,代码如下:

   <div id="app">
        <div v-test:msg.a.b="message"></div>
    </div>
    <script>
        Vue.directive('test', {
            bind: function (el, binding, vnode) {
                var keys = [];
                for(var i in vnode) {
                    keys.push(i);
                }
                el.innerHTML = 
                    'name:' + binding.name + '<br>' +
                    'value:' + binding.value + '<br>' +
                    'expression:' + binding.expression + '<br>' +
                    'argument:' + binding.arg + '<br>' +
                    'modifiers:' + JSON.stringify(binding.modifiers) + '<br>' +
                    'vnode keys:' + keys.join(',')
            }
        })

        var app = new Vue({
            el: '#app',
            data: {
                message: 'some text'
            }
        })
    </script>

执行后结果为:

name:test
value:some text
expression:message
argument:msg
modifiers:{"a":true,"b":true}
vnode keys:tag,data,children,text,elm,ns,context,fnContext,fnOptions,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder

在大多数场景,我们会在 bind 钩子里绑定一些事件,比如在 document 上用 addEventListrener 绑定,在unbind 里用 removeEventListener 解绑,比较典型的示例就是让这个元素随着鼠标拖拽。

如果需要多个值,自定义指令也可以传入一个 JavaScript 对象字面量,只要是合法类型的 JavaScript 表达式都是可以的。例如:

   <div id="app">
        <div v-test="{msg: 'hello', name: 'jj'}"></div>
    </div>
    <script>
        Vue.directive('test', {
            bind: function (el, binding, vnode) {
                console.log(binding.value.msg);
                console.log(binding.value.name);
            }
        })

        var app = new Vue({
            el: '#app',
        })
    </script>
作者:kindleheart
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/kindleheart/p/10009564.html