最近一直在忙着做项目,在这个过程中也遇到了很多问题,之前虽然也有做笔记总结,但从未发过文章,这是第一次尝试,既为分享,也为记录,写得不好请各位多多指正。
言归正传,相信大家经常都会遇到要处理表单验证的环节,而我在最近的项目中也遇到需要做表单验证的业务,在此做一下小菜鸟的分享。
先上效果图:
表单校验前的准备
首先可以先参考Element Plus官网表单组件的校验表单基本格式
地址:Form 表单 | Element Plus
准备过程总结为如下三步:
- 从element-plus中引入类型FormInstance和FormRules,并把表单对象的节点设置为FormInstance类型,表单内对所有参数约束的总规则(rules)设置为FormRules类型
- 定义包含表单内各参数的响应式数据对象ruleForm,并把ruleForm和rules在表单<el-form>标签的属性中进行单向数据绑定。此外需为表单参数对应的item设置相应的prop和v-model绑定对应ruleForm的参数
- 定义好提交表单的验证函数,官网例子中为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>
该案例个人代码如下:
<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
|
|
any | 可以是任何类型 |
但是仅仅靠type的限制是远远无法满足业务需求的,因此
pattern的存在就显得尤为重要,它代表着rule 属性指示值必须匹配才能通过验证的正则表达式。
通过正则表达式我们可以实现对手机号码、邮箱等各项数据的合法性进行最基本的正确性校验。
3.几个小小的注意点
-
要验证字段的确切长度,请指定len属性。如果该
len
属性与min
和max
范围属性结合使用,len
则优先。 -
使用min和max属性定义范围时,对于string和array类型是针对其length, 对应number类型则要求它的值不能小于min或大于max
-
此外如果需要验证深层对象属性,还可以通过将嵌套规则分配给规则的属性来验证属于
object
或类型的规则。
另一种的表单验证: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
个人总结:
本次项目中做表单验证的过程,我发现官方文档永远是咋们最可靠的帮手,看懂官方文档真的基本可以解决遇到的绝大部分问题。
最后,奉上我最近比较喜欢的一句话,从不胜利的人很少失败,从不攀登的人很少跌倒。希望大家都不畏失败,不怕跌倒。