如何在React TypeScript中实现无form标签的表单验证?
React TypeScript 无form标签的字段验证实现
下面是一个适合新手的完整实现,包含字符长度、邮箱、手机号验证,以及空字段提示,全程不用<form>标签:
import { useState } from 'react'; // 定义表单数据的TypeScript接口,约束字段类型 interface FormData { name: string; email: string; phone: string; } // 定义错误信息接口,对应每个字段的提示 interface FormErrors { name?: string; email?: string; phone?: string; } const FormValidation = () => { // 存储输入框的当前值 const [formData, setFormData] = useState<FormData>({ name: '', email: '', phone: '' }); // 存储各字段的错误提示 const [errors, setErrors] = useState<FormErrors>({}); // 单个字段的验证逻辑 const validateField = (field: keyof FormData, value: string): string | undefined => { // 空值检查 if (!value.trim()) { return `${field === 'name' ? '姓名' : field === 'email' ? '邮箱' : '手机号'}不能为空`; } // 不同字段的专属验证规则 switch (field) { case 'name': if (value.length < 2 || value.length > 10) { return '姓名长度需在2-10个字符之间'; } break; case 'email': // 基础邮箱格式正则 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(value)) { return '请输入有效的邮箱地址'; } break; case 'phone': // 国内11位手机号正则 const phoneRegex = /^1[3-9]\d{9}$/; if (!phoneRegex.test(value)) { return '请输入有效的11位手机号'; } break; } return undefined; }; // 输入框内容变化时的处理函数 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = e.target; // 更新对应字段的输入值 setFormData(prev => ({ ...prev, [name]: value })); // 实时验证当前字段(不想实时验证可以删掉这两行) const error = validateField(name as keyof FormData, value); setErrors(prev => ({ ...prev, [name]: error })); }; // 提交按钮点击事件 const handleSubmit = () => { // 统一验证所有字段,收集错误 const newErrors: FormErrors = {}; Object.keys(formData).forEach(key => { const field = key as keyof FormData; const error = validateField(field, formData[field]); if (error) { newErrors[field] = error; } }); setErrors(newErrors); // 没有错误时执行后续逻辑(比如发请求) if (Object.keys(newErrors).length === 0) { console.log('验证通过,表单数据:', formData); // 这里替换成你的提交逻辑 } }; return ( <div style={{ maxWidth: '400px', margin: '2rem auto', padding: '0 1rem' }}> {/* 姓名字段 */} <div style={{ marginBottom: '1rem' }}> <label htmlFor="name" style={{ display: 'block', marginBottom: '0.5rem' }}>姓名</label> <input type="text" id="name" name="name" value={formData.name} onChange={handleInputChange} // 验证不通过时边框变红 style={{ width: '100%', padding: '0.5rem', border: errors.name ? '1px solid red' : '1px solid #ccc' }} /> {/* 显示错误提示 */} {errors.name && <p style={{ color: 'red', margin: '0.25rem 0 0 0' }}>{errors.name}</p>} </div> {/* 邮箱字段 */} <div style={{ marginBottom: '1rem' }}> <label htmlFor="email" style={{ display: 'block', marginBottom: '0.5rem' }}>邮箱</label> <input type="email" id="email" name="email" value={formData.email} onChange={handleInputChange} style={{ width: '100%', padding: '0.5rem', border: errors.email ? '1px solid red' : '1px solid #ccc' }} /> {errors.email && <p style={{ color: 'red', margin: '0.25rem 0 0 0' }}>{errors.email}</p>} </div> {/* 手机号字段 */} <div style={{ marginBottom: '1rem' }}> <label htmlFor="phone" style={{ display: 'block', marginBottom: '0.5rem' }}>手机号</label> <input type="tel" id="phone" name="phone" value={formData.phone} onChange={handleInputChange} style={{ width: '100%', padding: '0.5rem', border: errors.phone ? '1px solid red' : '1px solid #ccc' }} /> {errors.phone && <p style={{ color: 'red', margin: '0.25rem 0 0 0' }}>{errors.phone}</p>} </div> {/* 提交按钮 */} <button onClick={handleSubmit} style={{ padding: '0.5rem 1rem', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }} > 提交 </button> </div> ); }; export default FormValidation;
关键部分说明
- TypeScript类型约束:用
FormData和FormErrors接口确保字段类型正确,避免新手常犯的类型错误 - 验证逻辑复用:
validateField函数统一处理所有字段的验证,空值检查优先,再执行字段专属规则 - 状态管理:用
useState分别存储输入值和错误信息,状态更新时用展开运算符保留其他字段的值 - 实时/提交验证可选:代码里默认是实时验证(输入时就提示错误),如果想改成只有点击提交才验证,删掉
handleInputChange里的验证代码即可 - 视觉反馈:验证不通过时输入框边框变红,并显示红色错误提示,用户体验更直观
内容的提问来源于stack exchange,提问作者user23506778
相关产品推荐
相关产品推荐

