Vue中的自定义指令directives

直接上代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>江河三千里</title>
    <script
      type="text/javascript"
      src="http://ljy0427.online/js/vue.js"
    ></script>
  </head>
  <body>
    <div id="root">
      <span v-rivers="name"></span>
      <!-- 函数式 -->
      <input type="text" v-frivers:value="nums" />
      <!-- 对象式 -->
    </div>
  </body>
  <script type="text/javascript">
    Vue.config.productionTip = false;
    var vm = new Vue({
      el: "#root",
      data: {
        name: "test",
        nums: 5,
      },
      directives: {
        rivers(item, res) {
          item.innerHTML = res.value;
          console.log(item, res);
        },
        frivers: {
          bind(item, res) {
            item.value = res.value;
            //   指令与元素成功绑定时触发
            console.log(item, res);
          },
          inserted(item, res) {
            //   指令所在元素被插入页面时
            item.focus()
          },
          updated(item, res) {
            item.value = res.value;
            //   指令所在的模板被重新解析时
            console.log(item, res);
          },
        },
      },
    });
  </script>
</html>

干货开始

可以看出来,在Vue中自定义指令的方式就是v-xxx,然后在directives中配置就可以了,并且配置的时候不用管v-,只用v-xxx中的xxx,而且这种配置有两种方式,一种是函数式,另一种是对象式

两种定义方式的区别

首先看两种方式的接受参数都是两个,那么这两个参数到底是什么呢?可以打印出来看看
item与res两个参数的差别
很明显的就可以看出来,第一个参数就是原生的dom结点,而第二个就是vue生成。

自定义指令就是操作真是的原生dom结点

函数式

rivers(item, res) {
   item.innerHTML = res.value;
   console.log(item, res);
}
看起来函数式很简单,但是也有一些缺陷,不过也是最常用的一种,而对象式就相对来说比较复杂了,但是其能完成函数式不能完成的东西。

对象式

frivers: {
    bind(item, res) {
    item.value = res.value;
    //   指令与元素成功绑定时触发
    console.log(item, res);
    },
    inserted(item, res) {
    //   指令所在元素被插入页面时
    item.focus()
    },
    updated(item, res) {
    item.value = res.value;
    //   指令所在的模板被重新解析时
    console.log(item, res);
    }
}
在对象式中,每个配置的名称都必须写对,其中有五个,这里只写了三个常用的,如下
  1. bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  2. inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  3. update:被绑定元素所在模板更新时调用,但是可能发生在其子 VNode 更新之前。
  4. componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
  5. unbind:只调用一次,指令与元素解绑时调用。

举例

前面说到了有些功能是函数不能完成的,而对象式是可以完成的。
例子:一个input框,通过自定义组件的形式绑定值,并且希望在页面一加载的时候,该input框自动获取焦点。
rivers(item, res) {
   item.innerHTML = res.value;
   item.focus()
   console.log(item, res);
}
就会有人说直接在函数里面加入获取焦点的时间,就如上代码就行了,其实这样是行不通的。
如果非要使用函数式完成该功能,可以添加一个定时器任务
rivers(item, res) {
   item.innerHTML = res.value;
   setTimeout(()=>{
   item.focus()
   },0)
   console.log(item, res);
}
添加了这个定时任务之后,就可以了,至于想知道为什么,可以去抖音关注一个博主叫“抖抖代码”,里面有很多编程相关的知识,有很多讲解都是不错的,这里我就把他解释这个input框原因的视频下载下来了

其实还可以通过对象式来完成,就是在inserted中加入起对应的逻辑代码即可。
至于产生的原因,就是js和vue的底层原理了

this关键字

先看下面代码
   directives: {
        rivers(item, res) {
          item.innerHTML = res.value;
          console.log("rivers", this);
        },
        frivers: {
          bind(item, res) {
              console.log("frivers", this)
            item.value = res.value;
            //   指令与元素成功绑定时触发
            console.log(item, res);
          },
          inserted(item, res) {
            //   指令所在元素被插入页面时
            item.focus()
          },
          updated(item, res) {
            item.value = res.value;
            //   指令所在的模板被重新解析时
            console.log(item, res);
          },
        },
      }
也就是输出当前的this,查看this指向
this指向
发现很奇怪,按理来说这里的this不应该是指向这个Vue实例么?但为什么指向的确是window
我的理解是,既然指令是操作真实的dom,那么this就没必要需要用vue来接管了,所以指向的还是window

全局自定义指令

在vue中的自定义指令,也可以定义全局的,方便其他的Vue实例来一起使用,定义方式也和过滤一样。
通过Vue.friver(),来添加对应的指令。
最后修改:2022 年 05 月 08 日