你写过自定义指令吗?自定义指令的应用场景有哪些?

1,069 阅读3分钟

这里我们主要从自定义指令是什么?自定义指令如何实现以及自定义指令的应用场景三个方面展开认识自定义指令

image.png

一、什么是自定义指令

Vue中提供了一套为数据驱动试图更为方便的操作,这些操作被成为指令系统。我们看到的v-开头的行内属性,都是指令,不同的指令可以完成或者实现不同的功能。除了核心功能默认内置的指令(v-model和v-show),Vue也允许注册自定义指令

指令使用的几种方式:

//会实例化一个指令,但是这个指令没有参数
v-xxx

//将值传到指令中
v-xxx="value:

//将字符串传到指令中,如v-html="'<p>内容</p>'"
v-xxx="string"

//使用修饰符(modifier)
v-xxx:arg.modifier="value"

二、如何实现

1.全局注册

注册一个自定义指令有全局注册和局部注册 全局注册主要是通过Vue.directive方法进行注册 Vue.derective第一个参数是指令的明治(不需要加上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数

//注册一个全局自定义指令'v-focus'
Vue.directive('focus',{
    //被绑定的元素插入到dom时...
    inserted:function(el){
        el.focus()//页面完成加载之后自动让输入框获取焦点的小功能
    }
})

2.局部注册

局部注册是通过组件options选择中设置directive属性

directive:{
    focus:{
        //定义的指令
        inserted:function(el){
            el.focus()//页面完成加载之后自动让输入框获取焦点的小功能
        }
    }
}

然后你就可以在模板中任何元素上使用新的v-focus property,如下:

<input v-focus/>

自定义指令也像组件那样存在钩子函数:

  • bind:只调用一次,指令第一次绑定到元素的时候调用,在这里可以进行一些初始化的设置
  • inserted:被绑定元素插入父节点时被调用(仅保证父节点存在,但不一定保证以及被插入文档中)
  • update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前
  • componentUpdate:指令所在组件VNode及其子VNode全部更新之后调用
  • unbind:只调用一次,指令与元素解绑时调用 所有的钩子函数的参数都有如下:
  • el:指令所绑定的元素,可以用来直接操作dom
  • binding:一个对象,包含以下property
    • name:指令名,不包含v-前缀
    • value:指令的绑定值,例如v-my-directive="1+1"中绑定值为2
    • oldValue:指令绑定的前一个值,仅在update个componentUpdated钩子中可用
    • expression:字符串形式指令表达式,例如v-my-directive="1+1",表达式为"1+1"
    • arg:传给指令的参数,可选,例如v-my-dircetive:foo中,参数为foo
  • vnode:Vue编译生成虚拟节点
  • oldVnode:上一个虚拟节点,尽在update和componentUpdate钩子中可用 除了el之外,其他参数都是只读的,切勿进行修改,如果需要在钩子之间共享数据,建议通过元素dataset来进行

举个例子:

<div v-demo="{color:'white',text:'hello'}"></div>

<script>
    Vue.directive('demo',binding){
        console.log(bing.value.color);//white
        console.log(bing.value.text);//hello
    }
</script>

三、应用场景

使用自定义指令可以满足我们日常的一次场景,这里给出几个自定义指令的案例:

  • 防抖
  • 图片懒加载
  • 一键copy

这里只举例以下输入框中的防抖实现

防抖这种情况设置一个v-throttle自定义指令来实现

//1.设置v-throttle自定义指令
Vue.directive('throttle', {
  bind: (el, binding) => {
    let throttleTime = binding.value; //防抖时间
    if (!throttleTime) {
      //用户若不设置防抖时间,默认为欸2s
      throttleTime = 2000;
    }
    let timer;
    el.addEventListener('click', event => {
      if (!timer) {
        //第一次执行
        timer = setTimeout(() => {
          timer = null
        }, throttleTime)
      } else {
        event && event.stopImmediatePropagation()
      }
    }, true)
  }
})
//2.为button标签设置v-throttle自定义指令
<button @click="sayHello" v-throttle>提交</button>