likes
comments
collection
share

vue3自定义指令验证输入

作者站长头像
站长
· 阅读数 67

vue3自定义指令验证输入

当我简单写几个带输入验证的input时,比如必填和邮件格式等,又不想引入antd那种大型库,就想试一下用vue的自定义指令来验证,确实效果嘎嘎好。

自定义指令

先来看一下自定义指令的基本语法

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。

一个指令的定义对象可以提供几种钩子函数 (都是可选的):

const myDirective = {
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
}

主要会用到的参数是el和binding,el是指令绑定到的元素,可以直接操作DOM,bingding是一个对象,包含value属性,是传递给指令的值。

实现

最终效果是这样 vue3自定义指令验证输入

模版

先简单写个模版,也不是那么简单,看input和hint就好了。

      <div class="form_field">
        <div class="field">
          <div class="field_label">email:</div>
          <input
            id="email"
            data-rules="required|email"
            v-validate="displayErrors"
            type="text"
          />
        </div>
        <div class="hint">{{ state.errors['email'] }}</div>
      </div>
      <div class="form_field">
        <div class="field">
          <div class="field_label">password:</div>
          <input
            id="password"
            data-rules="required|minLength:8"
            v-validate="displayErrors"
            type="password"
          />
        </div>
        <div class="hint">{{ state.errors['password'] }}</div>
      </div>

在data-rules中写上需要哪些验证,email是必填和邮箱格式,password是必填和长度至少为8。

自定义指令是v-validate,需要传递displayErrors函数过去,在这个函数里面可以拿到输入验证的结果,有error的话展现到页面上。hint就是展示错误的地方,需要拿到对应的error,这里的关键字要和input的id属性对应。

setup

setup部分比较简单,定义一个state,包含errors对象。displayErrors函数就是拿到验证结果,把错误放入erros中。

<script setup>
import { reactive } from 'vue';

const state = reactive({
  errors: {},
});
function displayErrors(errors) {
  if (errors) {
    state.errors[errors.name] = errors.error;
  }
}
</script>

自定义指令实现

接下来是重头戏了。在元素mounted了后,拿到rules。如果有rules,就监听元素的input事件,并验证每一条rule是不是符合,不符合的就给出error,并调用组件传过来displayErrors函数。

const validateDirective = {
  mounted(el, binding, vnode, prevVnode) {
    // 获取定义在dataset.rules的规则
    const rules = el.dataset['rules'];
    // 获取组件传递的displayErrors函数
    const displayErrors = binding.value;
    if (!rules) return;
    // 解析rules
    const specRules = getRules(rules);
    el.addEventListener('input', (e) => {
      // input的值
      const value = e.target.value;
      let error;
      if ('email' in specRules) {
        const emailRegex =
          /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
        if (!emailRegex.test(value)) {
          error = `字符串不符合邮件格式`;
        }
      }
      if ('minLength' in specRules) {
        if (value.length < specRules['minLength']) {
          error = `字符串长度至少为${specRules['minLength']}`;
        }
      }
      if ('required' in specRules) {
        if (!value) {
          error = '字符串不能为空';
        }
      }
      displayErrors({
        name: el.id,
        error: error,
      });
    });
  },
};

rules和getRules这里都是简单的实现。

function getRules(rules) {
  // rules用|分隔
  const validateRules = rules.split('|');
  const rulesObj = {};
  validateRules.forEach((rule) => {
    // rule参数用:分隔
    const specRule = rule.split(':');
    if (specRule.length > 1) {
      rulesObj[specRule[0]] = specRule[1];
    } else {
      // 没有参数的rule用true代表
      rulesObj[specRule[0]] = true;
    }
  });
  return rulesObj;
}

注册自定义指令

可以在main.js中全局注册自定义指令

import validateDirective from './directives/validate';
const app = createApp(App);
app.directive('validate', validateDirective);
app.mount('#app');

也可以通过directives选项注册

import validateDirective from './directives/validate';

export default {
  directives: {
    // 在模板中启用 v-validate
    validate: validateDirective
  }
}

总结

以上就是通过自定义指令验证输入的全部内容了。除了这个,自定义指令还有更多有趣又有用的功能,如v-copy, v-lazy-img,v-emoji,v-longpress等,可以参考这篇文章。当遇到需要通用的操作原生DOM的情况时,除了$refs,试试看自定义指令吧!

转载自:https://juejin.cn/post/7250382724879122489
评论
请登录