You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 01:42:23