使用 async-validator 自定义 vue3 的表单验证

875 阅读3分钟

async-validator 是个表单校验库

官网:github.com/yiminghe/as…

安装async-validator

npm i async-validator

我们的目标完成一个表单验证,如下:

image.png

上代码:

先定义一个hooks,validator.ts 里面封装了async-validator的validate方法,底下有2个辅助函数是为了在界面展示错误信息

import AsyncValidator, { type Rules } from 'async-validator'

/**
 *
 * @param value 整个表单值
 * @param rules 校验规则
 * @param key 传入key 怎验证单行,否则验证整个表单
 * @returns
 */
export const useValidator = (form: any, rules: Rules, key?: string) => {
  let _rules: any = {}
  if (key) {
    _rules[key] = rules[key]
  } else {
    _rules = rules
  }
  const validator: AsyncValidator = new AsyncValidator(_rules)

  return validator
    .validate(form.value)
    .then(() => {
      // 验证通过
      clearErrorMsg(form, key)
      return { valid: true }
    })
    .catch(({ errors }) => {
      setErrorMsg(errors, form, key)
      return { valid: false, errors }
    })
}

// 设置界面错误展示信息
const setErrorMsg = (errors: any, form: any, key?: string) => {
  if (key) {
    form.value[key + 'Msg'] = errors[0].message
  } else {
    errors.forEach((error: { field: string; message: any }) => {
      form.value[error.field + 'Msg'] = error.message
    })
  }
}

// 验证通过将错误置空
const clearErrorMsg = (form: any, key?: string) => {
  if (key) {
    form.value[key + 'Msg'] = ''
  } else {
    Object.keys(form.value).forEach((itemKey) => {
      if (itemKey.endsWith('Msg')) {
        form.value[itemKey + 'Msg'] = ''
      }
    })
  }
}


表单组件 ValidatorView.vue

<template>
  <div class="main">
    <h2>vue3 表单验证</h2>

    <form>
      <div>
        <label class="label">账号</label>
        <a-input
          type="text"
          v-model:value="form.account"
          @blur="handleBlurAccount"
          placeholder="请输入账号"
          class="input"
        />
        <div class="error">{{ form.accountMsg }}</div>
      </div>
      <div>
        <label class="label">密码</label>
        <a-input
          tyep="password"
          v-model:value="form.password"
          @blur="handleBlurPassword"
          type="text"
          class="input"
          placeholder="请输入密码"
        />
        <div class="error">{{ form.passwordMsg }}</div>
      </div>

      <div>
        <a-button class="submit-btn" type="primary" @click="submit">保存</a-button>
      </div>
    </form>
  </div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Input as AInput, Button as AButton } from 'ant-design-vue'
import { useValidator } from '@/hooks/validator'

// 验证表单
const form = ref({
  account: '',
  password: '',
  accountMsg: '', // 用来展示错误信息
  passwordMsg: '' // 用来展示错误信息
})

// 验证规则
const rules = {
  account: [{ required: true, message: '请输入账号' }],
  password: [{ required: true, message: '请输入密码' }]
}

// 验证函数
const validatorFn = (key?: string) => {
  return useValidator(form, rules, key)
}

// 账户失去焦点验证,单个表单行校验
const handleBlurAccount = () => {
  validatorFn('account')
}

// 密码失去焦点验证,单个表单行
const handleBlurPassword = () => {
  validatorFn('password')
}

// 验证整个表单
const submit = () => {
  validatorFn().then((result: any) => {
    if (result.valid) {
      console.log('验证通过!', form.value)
    } else {
      console.log('验证失败', result.errors)
    }
  })
}
</script>

<style lang="css">
.main {
  margin: 10px 100px;
}
.label {
  padding-right: 10px;
  padding-left: 10px;
  display: inline-block;
  box-sizing: border-box;
  width: 100px;
  text-align: right;
}
.input {
  width: 200px;
  height: 30px;
  margin-top: 10px;
}
.submit-btn {
  margin-top: 10px;
  margin-left: 100px;
}
.error {
  color: red;
  height: 20px;
  margin-left: 100px;
  font-size: 12px;
}
</style>


在组件中,定义一个需要验证的表单form,并将form的属性绑定到表单元件input上去。还需要定义验证规则,验证规则跟form字段对应,然后定义了一个验证函数validatorFn,在需要验证的时机调它,validatorFn调用我们定义的hooks

这时候我们点击提交,看下控台,验证通过和不通过输出分别如下:

image.png image.png

如果有异步验证只需要增加一条带asyncValidator的规则:

// 验证规则
const rules = {
  account: [
    { required: true, message: '请输入账号' },
    {
      message: '账号已存在',
      asyncValidator: (_rule: any, value: string) => {
        return new Promise<void>((resolve, reject) => {
          setTimeout(() => {
            if (value === 'abc') {
              reject('isExist') // reject with error message
            } else {
              resolve()
            }
          }, 500)
        })
      }
    }
  ],
  password: [{ required: true, message: '请输入密码' }]
}

这时候可以加个loading属性,点击submit后出现一个loading效果,验证结束后消失

 <div>
    <a-button class="submit-btn" type="primary" @click="submit">保存</a-button>
    <span v-if="loading" class="loading">验证中...</span>
 </div>
      
const loading = ref(false);
// 验证整个表单
const submit = () => {
 loading.value = true;
  validatorFn().then((result: any) => {
    loading.value = false;
    if (result.valid) {
      console.log('验证通过!', form.value)
    } else {
      console.log('验证失败', result.errors)
    }
  })
}

效果如图:

image.png

以上就是自定义的表单验证内容,代码可以直接复制运行