Vue如何创建自定义指令?

前言

什么是vue指令了? Vue自带的指令很多,v-for/v-if/v-else/v-else-if/v-model/v-bind/v-on/v-show/v-html/v-text... 原来这就是指令。

但是这些指令都是比较偏向于工具化,有些时候在实现具体的业务逻辑的时候,发现不够用,如何来自定义指令?

全局指令

第一步

最好建立一个全局的命令文件例如:directive.js 利用Vue.directive()建立一个全局命令,并将它暴露出来,例如一个focus 让表单自动聚焦

// directive.js
import Vue from 'vue';

const focus = Vue.directive('focus', {
    // 指令的钩子函数--第一次绑定元素时调用
    bind(el) {
        console.warn('指令的钩子函数:bind');
        console.log(el);
    },
    /**
    * inserted 在元素被插入到页面中的时候调用---vm实例的钩子函数
    * binding是一个对象,包括指令的所有信息
    */
    inserted: function (el, binding) {
        el.focus();
        el.setAttribute('placeholder', 'web秀');
        // 自动聚焦,input提示placeholder输入 "web秀"

        // 其中foo是指令参数--可以打印看看
        console.log(binding.arg);
    },
    // 指令的钩子函数,只调用一次,指令与元素解绑时调用(即当标签被删除时)。
    unbind() {
        // 当指令所在的元素,从页面中移除的时候,unbind钩子函数会被执行
        console.warn('指令的钩子函数:unbind');
    }
})

export {focus}

第二步

在main.js(入口JS文件)中将它引入,可以省略文件后缀

// main.js
import focus from 'xxx/directive'

这样任何一个Vue文件只有使用v-focus(指令名),就可以很方便的自动聚焦了。

<input type="text" v-focus:foo="我是指令参数">

局部指令

用法和全局指令一样,只是在单个Vue实例页面内部定义,只能被这一个实例使用,而全局可以被多个实例使用。

<div>
    <input type="text" v-focus:foo="我是指令参数">
</div>

<script>
var vm = new Vue({
  el: '#app',
  data: {
  },
  directives:{
    focus:{
      // 创建局部指令
      inserted: function (el, binding) {
        el.focus();
        el.setAttribute('placeholder', 'web秀');
      })
    }
  }
})
</script>

自定义指令钩子函数参数介绍

函数

  1. bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  2. inserted:被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
  3. update:所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  4. componentUpdated:所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
  5. unbind:只调用一次,指令与元素解绑时调用。

参数

  1. el:指令所绑定的元素,可以用来直接操作 DOM 。
  2. 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 }。
  3. vnode:Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。
  4. oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

学以致用

最后我们来写一个非常实用的栗子,页面倒计时,请上眼

function padZero(number) {
  let tmp = "0" + number;
  return tmp.slice(-2, tmp.length);
}

function countDown(diff) {
  // 剩余毫秒
  let millisecond = diff % 1000;
  // 总秒
  let seconds = (diff - millisecond) / 1000;
  // 剩余秒数
  let realseconds = seconds % 60;
  // 剩余分钟数
  let minutes = (seconds - realseconds) / 60;
  // let realminutes = seconds % 60;
  // let hours = (diff - minutes - seconds) % 86400;
  return diff >= 0 ? padZero(minutes) + "分" + padZero(realseconds) + "秒" : "";
}
...
directives: {
    timer: {
      inserted(el, binding, vnode) {
        const me = vnode.context;
        const flight = me.$store.state.flight;
        // 获取参数,截止时间与当前时间差(单位毫秒)
        let val = +binding.value;
        let timer = window.setInterval(() => {
          val -= 1000; // 每秒减1000毫秒/1秒
          let instance = countDown(val);
          if (!instance) {
            // 倒计时结束,do something
            if (timer) {
              window.clearInterval(timer);
              timer = null;
            }
            return;
          }
          // 格式化的日期插入到页面
          el.innerHTML = instance;
        }, 1000);
      }
    }
}
...

页面可以直接使用

<!-- 截止时间与当前时间差(单位毫秒) -->
<span v-timer='100000'></span>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏WriteOnRead

JDK源码分析-CyclicBarrier

CyclicBarrier 是并发包中的一个工具类,它的典型应用场景为:几个线程执行完任务后,执行另一个线程(回调函数,可选),然后继续下一轮,如此往复。

6620
来自专栏一猿小讲

吐槽,Java 设计的槽点

你是否曾经在面试的时候,经常被问到:数组有没有 length() 方法?字符串有没有 length() 方法? 集合有没有 length() 方法?

6110
来自专栏WriteOnRead

JDK源码分析-CountDownLatch

CountDownLatch 是并发包中的一个工具类,它的典型应用场景为:一个线程等待几个线程执行,待这几个线程结束后,该线程再继续执行。

9420
来自专栏程序亦非猿

AsyncListDiffer-RecyclerView最好的伙伴

导读,近些年来 Android 一直在优化 RecyclerView 刷新效率,相继出了 DiffUtil,AsyncListDiffer ,我在我的开源库 F...

13510
来自专栏智能计算时代

「微前端架构」微前端-Angular风格-第2部分

在前一部分中,我讨论了转向MFE解决方案的动机以及解决方案相关的一些标准。在这一部分中,我将介绍我们如何在Outbrain实现它。

11420
来自专栏大数据手稿笔记

浅谈HBase region的单点问题

https://www.cnblogs.com/yhxx511/p/9609765.html

8030
来自专栏AI科技时讯

受欢迎的五个开源可视化工具——你的选择是?

人工智能时代,数据和算法以及硬件资源是非常重要的,相关行业的大公司也越来越关注数据中蕴含的价值,数据的收集和应用比以前任何时候都看得更加重要,甚至...

7920
来自专栏曲奇泡芙

端与云的融合

端、管、云,物联网系统的三个主要构成元素,各自技术在高速发展的同时也在不断的影响着现代物联网系统的设计。

16120
来自专栏一猿小讲

经验分享一箩筐,从此再也不入坑

多用户并发情况下,CPU 利用率长期为100%,DUMP 线程信息,发现 CPU 利用率高的线程都与 HashMap 操作相关。

11440
来自专栏WriteOnRead

JDK源码分析-Lock&Condition

涉及多线程问题,往往绕不开「锁」。在 JDK 1.5 之前,Java 通过 synchronized 关键字来实现锁的功能,该方式是语法层面的,由 JVM 实现...

6210

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励