vue2之自定义指令

1,095 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情

上一篇我们介绍过vue里面的内置指令,但是很多时候时候内置指令不能满足我们的需求开发,因此vue给我们提供了自定义指令的配置项,这样我们就可以根据需求自定义指令,自定义的指令在模板中的用法和内置指令是一样的。

定义自定义指令

1. 全局指令和局部指令

自定义指令和过滤器一样,按照作用域来划分也分为两种:全局指令和局部指令

定义全局指令

Vue.directive(指令名,配置对象)

或者

Vue.directive(指令名,回调函数)

定义局部指令

directives: {
    指令名: 配置对象
}

或者

directives() {
}

2. 函数式自定义指令和对象式自定义指令

自定义指令可以按照两种方式去配置:函数式和对象式

函数式自定义指令

函数式指令就是将指令定义成回调函数,这样在触发的时候就会触发回调函数,回调函数包含两个参数:el和binding。

基本写法

<template>
  <div class="test-wrapper">
    <div v-test>自定义指令</div>
  </div>
</template>
<script>
export default {
  data () {
    return {
    };
  },
  directives: {
    test(el, binding) {
      console.log('el', el);
      console.log('binding', binding);
    }
  }
};

根据打印信息,我们可以看到el表示dom元素,binding表示包含元素有关的所有属性的对象

1670750628475.png

传递参数

指令也是可以传递参数的

<template>
  <div class="test-wrapper">
    <div v-test="number">自定义指令</div>
    <div>number的值: {{number}}</div>
    <button @click="addNumber">增加number</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      number: 1
    };
  },
  directives: {
    test(el, binding) {
      console.log('el', el);
      console.log('binding', binding);
    }
  },
  methods: {
    addNumber() {
      this.number++;
    }
  }
};
</script>

参数binding的value属性可以拿到传递过来的参数。效果如下:

image.png

如果这个参数被组件中别的部分修改了,那么指令也会被执行,而且能拿到最新的值。比如增加number的值,参数也变了。效果如下:

image.png

对象式自定义指令

对象式也就是在指定定义对象中添加几个钩子函数,这些钩子都是可选的。

  • bind: 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
  • inserted: 被绑定元素插入父节点时调用(仅保证父节点存在,但不一定被插入文中)
  • update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令的值可能发生变化也有可能没有。
  • componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用
  • unbind: 只调用一次,指令与元素解绑时调用

这些钩子函数具有以下参数:

  • el: 指令所绑定的元素,可以用来直接操作DOM
  • binding: 一个包含元素属性的对象
  • vnode: Vue编译生成的虚拟节点
  • oldVnode: 上一个虚拟节点,仅在update和componentUpdated钩子中使用
<template>
  <div class="test-wrapper">
    <div>number的值: {{number}}</div>
    <button @click="addNumber">增加number</button>
    <input type="text" v-test="number">
  </div>
</template>
<script>
export default {
  data () {
    return {
      number: 1
    };
  },
  directives: {
    test: {
      bind(el, binding) {
        el.value = binding.value;
      },
      inserted(el, binding) {
        el.focus();
      },
      update(el, binding) {
        el.value = binding.value;
      }
    }
  },
  methods: {
    addNumber() {
      this.number++;
    }
  }
};
</script>

初始化的时候,会执行bind和inserted,效果如下:

image.png

改变number的值,会执行update,效果如下:

image.png

小结

  1. 函数式定义指令相当于是简写版,只会在初始化和模板变化(解析)的时候被触发,而对象式可以根据钩子函数在特定的时候执行对应的操作
  2. 指令定义的时候不加v-, 但使用时要加v-
  3. 指令名如果时多个单词,要使用kebab-case命名方式,不要用驼峰命名。