最近一直在忙着做项目,在这个过程中也遇到了很多问题,之前虽然也有做笔记总结,但从未发过文章,这是第一次尝试,既为分享,也为记录,写得不好请各位多多指正。

言归正传,相信大家经常都会遇到要处理表单验证的环节,而我在最近的项目中也遇到需要做表单验证的业务,在此做一下小菜鸟的分享。

先上效果图:

在Vue框架项目里通过Element Plus实现表单验证

在Vue框架项目里通过Element Plus实现表单验证

表单校验前的准备

首先可以先参考Element Plus官网表单组件的校验表单基本格式

地址:Form 表单 | Element Plus

准备过程总结为如下三步:

  1. 从element-plus中引入类型FormInstance和FormRules,并把表单对象的节点设置为FormInstance类型,表单内对所有参数约束的总规则(rules)设置为FormRules类型
  2. 定义包含表单内各参数的响应式数据对象ruleForm,并把ruleForm和rules在表单<el-form>标签的属性中进行单向数据绑定。此外需为表单参数对应的item设置相应的prop和v-model绑定对应ruleForm的参数
  3. 定义好提交表单的验证函数,官网例子中为submitForm函数和resetForm函数
<template>
  <div id="validator-form">
<!-- 以此为例 为表单对象设置ref以便后续获取该节点对象 
    并为表单对象添加ruleForm和rules的单向数据绑定 此外给姓名参数的item添加name的prop
    以及v-model数据双向绑定ruleForm对应名的参数-->
    <el-form
      ref="ruleFormRef"  
      :model="ruleForm"
      :rules="rules"
      label-width="520px"
      class="demo-ruleForm"
      :size="formSize"
      status-icon
    >
        <el-form-item label="姓名" prop="name">
        <el-input v-model="ruleForm.name" placeholder="请输入名字"/>
      </el-form-item>
...
 </el-form>
  </div>
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
// 引入类型
import type { FormInstance, FormRules } from "element-plus";
const formSize = ref("default");
// 获取表单对象并设置为FormInstance类型
const ruleFormRef = ref<FormInstance>();
// 定义包含表单内各参数的响应式数据对象 用于保存表单参数
const ruleForm = reactive({
  name: "",
  sex: "",
  height:"",
  weight:"",
  phone: "",
  time: "",
  email: "",
  birthday:""
});
// 定义包含所有参数规则的rules常量并设置为FormRules类型
const rules = reactive<FormRules>({...})
...
// 表单校验函数
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate((valid, fields) => {
    if (valid) {
        // 校验成功
      console.log("submit!");
    } else {
        // 校验失败
      console.log("error submit!", fields);
    }
  });
};
//清除校验效果并且清空表单参数的函数
const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.resetFields();
};
</script>

在Vue框架项目里通过Element Plus实现表单验证

在Vue框架项目里通过Element Plus实现表单验证

该案例个人代码如下:

<template>
  <div id="validator-form">
    <!-- 以此为例 为表单对象设置ref以便后续获取该节点对象 -->
    <el-form
      ref="ruleFormRef"  
      :model="ruleForm"
      :rules="rules"
      label-width="520px"
      class="demo-ruleForm"
      :size="formSize"
      status-icon
    >
      <el-form-item label="姓名" prop="name">
        <el-input v-model="ruleForm.name" placeholder="请输入名字"/>
      </el-form-item>
      <el-form-item label="性别" prop="sex">
        <el-select v-model="ruleForm.sex" placeholder="请选择性别">
          <el-option label="男" value="male" />
          <el-option label="女" value="female" />
        </el-select>
      </el-form-item>
      <el-form-item label="身高(cm)" prop="height">
        <el-input v-model.number="ruleForm.height" placeholder="请输入身高"/>
      </el-form-item>
      <el-form-item label="体重(kg)" prop="weight">
        <el-input v-model="ruleForm.weight" placeholder="请输入体重"/>
      </el-form-item>
      <el-form-item label="手机" prop="phone">
        <el-input v-model.number="ruleForm.phone" placeholder="请输入手机号码"/>
      </el-form-item>
      <el-form-item label="邮箱" prop="email">
        <el-input v-model="ruleForm.email" placeholder="请输入邮箱"/>
      </el-form-item>
      <el-form-item label="出生日期" required>
        <el-form-item prop="birthday">
          <el-date-picker
            v-model="ruleForm.birthday"
            type="date"
            label="Pick a date"
            placeholder="请选择出生日期"
            style="width: 100%"
          />
        </el-form-item>
    </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm(ruleFormRef)"
          >提交</el-button
        >
        <el-button @click="resetForm(ruleFormRef)">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
// 引入类型
import type { FormInstance, FormRules } from "element-plus";
const formSize = ref("default");
// 获取表单对象并设置为FormInstance类型
const ruleFormRef = ref<FormInstance>();
// 包含表单内各参数的响应式数据对象 用于保存表单参数
const ruleForm = reactive({
  name: "",
  sex: "",
  height:"",
  weight:"",
  phone: "",
  time: "",
  email: "",
  birthday:""
});
// 定义包含所有参数规则的rules常量并设置为FormRules类型
const rules = reactive<FormRules>({
  name: [
    { required: true,type:'string', message: "姓名不能为空", trigger: "blur" },
    { pattern:/[\u4e00-\u9fa5]/,min: 2, max: 15,transform(value){return value.trim()}, message: "姓名格式错误", trigger: "blur" },
  ],
  sex: [
    { required: true, message: "性别不能为空", trigger: "change" },
  ],
  height: [
    { required: true, message: "身高不能为空", trigger: "blur" },
    { min: 1, max: 300,type:"number", message: "身高范围为1~300", trigger: "blur" },
  ],
  weight: [
    { required: true, message: "体重不能为空", trigger: "blur" },
    { min: 2, max: 15, message: "体重范围为1~300", trigger: "blur" },
  ],
  phone: [
    { required: true, message: "手机不能为空", trigger: "blur" },
    { pattern:/^1[3|4|5|8|9]{1}[0-9]{9}$/,min: 2, max: 15, message: "手机格式错误", trigger: "blur" },
  ],
  email: [
    { required: true, message: "邮箱不能为空", trigger: "blur" },
    { pattern:/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,min: 2, max: 15, message: "邮箱格式错误", trigger: "blur" },
  ],
  birthday: [
    { required: true, message: "出生日期不能为空", trigger: "change" },
  ],
});
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate((valid, fields) => {
    if (valid) {
      console.log("submit!");
    } else {
      console.log("error submit!", fields);
    }
  });
};
const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.resetFields();
};
</script>
<style lang="less">
#validator-form {
  margin-top: 200px;
  width: 1500px;
  height: 900px;
  button{
    margin-top: 50px;
  }
  div{
    label{
      margin-top: 20px;
    }
    div{
      margin-top: 5px;
    }
  }
}
</style>

 

 表单校验的重点:定义规则

1.input输入框原生自带的type规则约束

例如type="password",原生自动的type类型可以参考这个:<input>:输入(表单输入)元素 - HTML(超文本标记语言) | MDN

2.根据不同参数指定对应的自定义规则

举一个简单的例子:

const rules = reactive<FormRules>({
  name: [
    { required: true,type:'string', message: "姓名不能为空", trigger: "blur" },
    { pattern:/[\u4e00-\u9fa5]/,min: 2, max: 15, message: "姓名格式错误", trigger: "blur" },
  ],
    // 也可以写出这种形式 需要定义validatename函数
    //name: [{ validator: validateName, trigger: 'blur' }],
    ...
})
/*
const validateName = (rule: any, value: any, callback: any) => {
  if (value === '') {
    callback(new Error('Please input the name'))
  } else {
    if (ruleForm.name !== '') {
      if (!ruleFormRef.value) return
      ruleFormRef.value.validateField('checkPass', () => null)
    }
    callback()
  }
}  */

required:是否为必填项,如不设置,则会根据校验规则确认。

type的类型与原生input的type类型不同,它限制对应参数的类型,其可选项有如下:

string 必须是类型string
number  必须是类型number
boolean 必须是类型boolean
method 必须是类型function
regexp 必须是RegExp创建新的时不产生异常的实例或字符串RegExp
integer 必须是类型number和整数
float 必须是类型number和浮点数
array 必须是由 确定的数组Array.isArray
object 必须是 typeobject而不是Array.isArray
enum 值必须存在于enum
date 值必须是有效的Date
url 必须是类型url
hex 必须是类型hex
email 必须是类型email
any 可以是任何类型

但是仅仅靠type的限制是远远无法满足业务需求的,因此

pattern的存在就显得尤为重要,它代表着rule 属性指示值必须匹配才能通过验证的正则表达式。

通过正则表达式我们可以实现对手机号码、邮箱等各项数据的合法性进行最基本的正确性校验。

3.几个小小的注意点

另一种的表单验证:async-validator

其基本用法是:定义描述符,将其分配给模式并将要验证的对象和回调函数传递给validate模式。

与上述的方法在规则限定上大体相识,使用前记得先install async-validator,其他啥也别说,先上例子:

import Schema from 'async-validator';
const descriptor = {
  name: {
    type: 'string',
    required: true,
    validator: (rule, value) => value === 'muji',
  },
  age: {
    type: 'number',
    asyncValidator: (rule, value) => {
      return new Promise((resolve, reject) => {
        if (value < 18) {
          reject('too young');  // reject with error message
        } else {
          resolve();
        }
      });
    },
  },
};
const validator = new Schema(descriptor);
validator.validate({ name: 'muji' }, (errors, fields) => {
  if (errors) {
    // validation failed, errors is an array of all errors
    // fields is an object keyed by field name with an array of
    // errors per field
    return handleErrors(errors, fields);
  }
  // validation passed
});
// PROMISE USAGE
validator.validate({ name: 'muji', age: 16 }).then(() => {
  // validation passed or without error message
}).catch(({ errors, fields }) => {
  return handleErrors(errors, fields);

除了可以像常规方法以对象的形式那般使用type、pattern正则表达式限制,它还可以以函数的形式使用,代码如下:

import Schema from 'async-validator';
const descriptor = {
  name(rule, value, callback, source, options) {
    const errors = [];
    if (!/^[a-z0-9]+$/.test(value)) {
      errors.push(new Error(
        util.format('%s must be lowercase alphanumeric characters', rule.field),
      ));
    }
    return errors;
  },
};
const validator = new Schema(descriptor);
validator.validate({ name: 'Firstname' }, (errors, fields) => {
  if (errors) {
    return handleErrors(errors, fields);
  }
  // validation passed
});

如果业务十分复杂,有多重验证的话,使用这个方法会更合适,通过官方文档给出的example可以清晰看到该方法可以使规则成为对象数组,代码如下:

const descriptor = {
  email: [
    { type: 'string', required: true, pattern: Schema.pattern.email },
    { 
      validator(rule, value, callback, source, options) {
        const errors = [];
        // test if email address already exists in a database
        // and add a validation error to the errors array if it does
        return errors;
      },
    },
  ],
};

官方文档地址:GitHub - yiminghe/async-validator: validate form asynchronous

个人总结:

本次项目中做表单验证的过程,我发现官方文档永远是咋们最可靠的帮手,看懂官方文档真的基本可以解决遇到的绝大部分问题。

最后,奉上我最近比较喜欢的一句话,从不胜利的人很少失败,从不攀登的人很少跌倒。希望大家都不畏失败,不怕跌倒。

发表回复