前言:

网站中的input输入框使用非常广泛,因业务场景不同需要对输入框做合法性校验或限制输入,比如电话号码、邮件、区号、身份证号等。input框的不合法内容主要有两种方式处理:1.用户输入内容后,通过规则验证告知用户不合法,2.禁止输入不符合规则字符。下面基于第2种情况,针对Vue中的input控件通过自定义指令(directive),使用正则表达式限制input控件的输入。

工作流程:

input控件绑定v-model ---> 通过自定义指令(v-restrict)设定验证的正则表达式 ---> 监控控件的keyup、keydown、paste事件,验证字符合法性 ---> 替换非法字符 ---> 替换后的结果更新绑定到v-model的变量里

控件元素代码:

<v-text-field label="Test"
      v-model="testtext"
      v-restrict="/[^a-zA-Z0-9]/g"
</v-text-field>

自定义指令(directive)代码:

import Vue from "vue";

Vue.directive("restrict", {
  bind(el, binding) {
    const target =
      el instanceof HTMLInputElement ? el : el.querySelector("input");
    target.addEventListener("keydown", e => {
      if (binding.value) {
        // Regex check
        if (binding.value.test(e.target.value)) {
          e.target.value = e.target.value.replace(binding.value, "");
          e.target.dispatchEvent(new Event("input"));//调用input事件使vue v-model绑定更新,下面相同
        }
      }
    });
    target.addEventListener("paste", e => {
      if (binding.value) {
        // Regex check
        if (binding.value.test(e.target.value)) {
          e.target.value = e.target.value.replace(binding.value, "");
          e.target.dispatchEvent(new Event("input"));
        }
      }
    });
    target.addEventListener("keyup", e => {
      if (binding.value) {
        // Regex check
        if (binding.value.test(e.target.value)) {
          e.target.value = e.target.value.replace(binding.value, "");
          e.target.dispatchEvent(new Event("input"));
        }
      }
    });
  } // end bind
}); // end directive

v-model本质及实现原理

通过下面两行代码给input输入框绑定值并添加事件钩子:

antdesign vue form 正则表达式校验_Vue

这实际上就是 input 实现 v-model 的精髓,通过修改 AST 元素,给 el 添加一个 prop,相当于我们在 input 上动态绑定了 value又给 el 添加了事件处理,相当于在 input 上绑定了 input 事件,其实转换成模板如下:

antdesign vue form 正则表达式校验_自定义指令_02

其实就是动态绑定了 input 的 value 指向了 messgae 变量,并且在触发 input 事件的时候去动态把 message 设置为目标值,这样实际上就完成了数据双向绑定了,所以说 v-model 实际上就是语法糖。

通过下面的window.getEventListeners(obj)就能看出在这个控件上绑定了input方法,当通过监听事件修改e.target.value时,并未调用input方法,所以v-model的值没有变化,需要通过代码(e.target.dispatchEvent(new Event("input"));)手动触发input事件。

 

下面代码可以验证e.target.value变化与v-model的联动变化过程:

antdesign vue form 正则表达式校验_自定义指令_03

antdesign vue form 正则表达式校验_自定义指令_04

Vue template code:
<v-text-field label="Test"
      v-model="testtext"
      @keyup="testkeyup($event)">
      <v-icon medium
        slot="append"
        @click.native="test()">save</v-icon>
</v-text-field>

Vue script code:
 data{testtext: "zsl"}
 methods: {
    test() {
      this.testtext += "a";
    },
    testkeyup(e) {
      e.target.value += "b";
      var eventb = new Event("input");
      e.target.dispatchEvent(eventb);
      console.log(
        "e.target.value: " +
          e.target.value +
          " | this.testtext: " +
          this.testtext
      );
    }
}

View Code

 

获取某元素绑定的所有事件(Listener)

通过Chrome中,在Console窗口里,通过window.getEventListeners(obj)获取某个元素绑定的所有事件(listener)

 

e.target.value的修改(change)不会自动调用vue的input方法,通过dispatchEvent的方式手动调用

e.target.dispatchEvent(new Event("input"));