先上代码
<script setup>
import { reactive, computed } from "vue";
const formData = reactive({
student: {
name: "",
gender: "",
age: null,
isValid: computed(() => {
return (
formData.student.name &&
formData.student.gender &&
formData.student.age >= 6 &&
formData.student.age <= 25
);
}),
},
parent: {
name: "",
phone: "",
isValid: computed(() => {
return (
formData.parent.name && /^1[3-9]\d{9}$/.test(formData.parent.phone)
);
}),
},
});
const errors = reactive({
student: {
name: "",
gender: "",
age: "",
},
parent: {
name: "",
phone: "",
},
});
const validateStudentName = () => {
if (!formData.student.name) {
errors.student.name = "姓名不能为空";
} else if (formData.student.name.length < 2) {
errors.student.name = "姓名至少2个字符";
} else {
errors.student.name = "";
}
};
const validateStudentAge = () => {
if (!formData.student.age) {
errors.student.age = "年龄不能为空";
} else if (formData.student.age < 6) {
errors.student.age = "年龄不能小于6岁";
} else if (formData.student.age > 25) {
errors.student.age = "年龄不能大于25岁";
} else {
errors.student.age = "";
}
};
const validateParentPhone = () => {
if (!formData.parent.phone) {
errors.parent.phone = "手机号不能为空";
} else if (!/^1[3-9]\d{9}$/.test(formData.parent.phone)) {
errors.parent.phone = "请输入有效的手机号";
} else {
errors.parent.phone = "";
}
};
const submit = () => {
validateStudentName();
validateStudentAge();
validateParentPhone();
if (formData.student.isValid && formData.parent.isValid) {
alert("表单验证通过");
} else {
alert("请检查表单填写");
}
};
</script>
<template>
<form @submit.prevent="submit">
<fieldset>
<legend>学生基本信息</legend>
<div class="form-group">
<label for="student-name">学生姓名:</label>
<input
id="student-name"
v-model="formData.student.name"
@blur="validateStudentName"
placeholder="请输入学生姓名"
/>
<span class="error">{{ errors.student.name }}</span>
</div>
<div class="form-group">
<label for="student-gender">学生性别:</label>
<select id="student-gender" v-model="formData.student.gender">
<option value="">请选择性别</option>
<option value="male">男</option>
<option value="female">女</option>
</select>
<span class="error">{{ errors.student.gender }}</span>
</div>
<div class="form-group">
<label for="student-age">学生年龄:</label>
<input
id="student-age"
type="number"
v-model.number="formData.student.age"
@blur="validateStudentAge"
placeholder="6-25岁"
/>
<span class="error">{{ errors.student.age }}</span>
</div>
</fieldset>
<fieldset>
<legend>家长联系信息</legend>
<div class="form-group">
<label for="parent-name">家长姓名:</label>
<input
id="parent-name"
v-model="formData.parent.name"
placeholder="请输入家长姓名"
/>
<span class="error">{{ errors.parent.name }}</span>
</div>
<div class="form-group">
<label for="parent-phone">联系电话:</label>
<input
id="parent-phone"
v-model="formData.parent.phone"
@blur="validateParentPhone"
placeholder="11位手机号码"
/>
<span class="error">{{ errors.parent.phone }}</span>
</div>
</fieldset>
<button type="submit">提交表单</button>
</form>
</template>
<style scoped>
form {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
fieldset {
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
legend {
padding: 0 10px;
font-weight: bold;
}
.form-group {
margin-bottom: 15px;
}
label {
display: inline-block;
width: 100px;
text-align: right;
margin-right: 10px;
}
input,
select {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
width: 200px;
}
.error {
color: red;
font-size: 12px;
margin-left: 110px;
display: block;
}
button {
padding: 10px 20px;
background: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #369f6b;
}
</style>
本文将基于提供的学生信息表单代码,详细讲解如何使用Vue3原生方式实现表单验证功能。这个实现方案不依赖任何第三方验证库,完全使用Vue3的响应式特性和原生JavaScript实现。
表单验证的核心设计
1. 数据结构设计
表单数据使用Vue3的reactive创建响应式对象,分为学生信息和家长信息两个部分:
const formData = reactive({
student: {
name: "",
gender: "",
age: null,
isValid: computed(() => { /* 验证逻辑 */ })
},
parent: {
name: "",
phone: "",
isValid: computed(() => { /* 验证逻辑 */ })
}
})
每个字段都有对应的isValid计算属性,用于实时判断该部分数据是否有效。
2. 错误信息管理
单独定义errors对象来存储验证错误信息:
const errors = reactive({
student: {
name: "",
gender: "",
age: "",
},
parent: {
name: "",
phone: "",
}
})
这种结构与表单数据保持一致的层级关系,便于管理和访问。
验证函数实现
1. 学生姓名验证
const validateStudentName = () => {
if (!formData.student.name) {
errors.student.name = "姓名不能为空";
} else if (formData.student.name.length < 2) {
errors.student.name = "姓名至少2个字符";
} else {
errors.student.name = "";
}
};
验证逻辑:
- 非空检查
- 最小长度检查
- 验证通过时清空错误信息
2. 学生年龄验证
const validateStudentAge = () => {
if (!formData.student.age) {
errors.student.age = "年龄不能为空";
} else if (formData.student.age < 6) {
errors.student.age = "年龄不能小于6岁";
} else if (formData.student.age > 25) {
errors.student.age = "年龄不能大于25岁";
} else {
errors.student.age = "";
}
};
验证逻辑:
- 非空检查
- 最小值检查
- 最大值检查
- 验证通过时清空错误信息
3. 家长手机号验证
const validateParentPhone = () => {
if (!formData.parent.phone) {
errors.parent.phone = "手机号不能为空";
} else if (!/^1[3-9]\d{9}$/.test(formData.parent.phone)) {
errors.parent.phone = "请输入有效的手机号";
} else {
errors.parent.phone = "";
}
};
验证逻辑:
- 非空检查
- 正则表达式验证手机号格式
- 验证通过时清空错误信息
表单提交处理
const submit = () => {
validateStudentName();
validateStudentAge();
validateParentPhone();
if (formData.student.isValid && formData.parent.isValid) {
alert("表单验证通过");
} else {
alert("请检查表单填写");
}
};
提交时执行所有验证函数,并检查各部分数据的isValid状态。
模板结构
模板使用标准的HTML表单元素,结合Vue指令:
<form @submit.prevent="submit">
<fieldset>
<legend>学生基本信息</legend>
<!-- 表单字段 -->
</fieldset>
<fieldset>
<legend>家长联系信息</legend>
<!-- 表单字段 -->
</fieldset>
<button type="submit">提交表单</button>
</form>
每个表单字段都绑定到对应的数据属性和验证函数:
<input
id="student-name"
v-model="formData.student.name"
@blur="validateStudentName"
placeholder="请输入学生姓名"
/>
<span class="error">{{ errors.student.name }}</span>
样式设计
样式部分使用scoped CSS,确保只影响当前组件:
.form-group {
margin-bottom: 15px;
}
.error {
color: red;
font-size: 12px;
margin-left: 110px;
display: block;
}
/* 其他样式... */
实现优势
- 响应式验证:利用Vue3的响应式系统,数据变化自动触发界面更新
- 即时反馈:通过
@blur事件在用户离开输入框时立即验证 - 结构化设计:数据和错误信息采用相同结构,便于维护
- 计算属性:使用
computed实现自动验证状态计算 - 原生实现:不依赖第三方库,减少项目体积和依赖