You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ant Design表单如何为区块添加统一的自定义校验错误提示

Ant Design表单如何为区块添加统一的自定义校验错误提示

嘿,这个需求我之前做项目的时候刚好碰到过,Ant Design虽然没有直接提供「区块级统一错误提示」的内置组件,但用它自带的表单API就能轻松实现,比你想的useState标记方案更贴合框架逻辑,我给你详细讲讲:

核心思路:批量校验区块内字段 + 维护区块错误状态

Antd的Form提供了validateFields方法,可以指定一组字段进行批量校验,我们可以利用这个API来校验整个区块的字段,然后根据校验结果在区块标题处显示统一的自定义错误。

具体实现代码示例

下面是一个完整的可运行示例,涵盖了实时校验和提交前校验两种场景:

import { Form, Input, Button } from 'antd';
import { useState } from 'react';

const SectionedForm = () => {
  // 获取表单实例
  const [form] = Form.useForm();
  // 维护各个区块的错误状态
  const [sectionErrors, setSectionErrors] = useState({
    firstSection: false,
    secondSection: false
  });
  const isRequired = true;

  // 封装区块校验通用函数
  const validateSection = async (sectionName, fieldList) => {
    try {
      // 批量校验指定字段
      await form.validateFields(fieldList);
      // 校验通过,清除区块错误状态
      setSectionErrors(prev => ({ ...prev, [sectionName]: false }));
      return true;
    } catch (errorInfo) {
      // 校验失败,标记区块错误状态
      setSectionErrors(prev => ({ ...prev, [sectionName]: true }));
      return false;
    }
  };

  // 提交表单时的校验逻辑
  const handleSubmit = async () => {
    // 依次校验所有区块
    const isFirstValid = await validateSection('firstSection', [
      ["firstSection", "name"],
      ["firstSection", "phoneNumber"],
      ["firstSection", "fax"],
      ["firstSection", "address"],
      ["firstSection", "country"]
    ]);
    const isSecondValid = await validateSection('secondSection', [
      ["secondSection", "city"]
    ]);

    if (isFirstValid && isSecondValid) {
      // 所有区块校验通过,执行提交逻辑
      console.log('表单校验通过,提交数据:', form.getFieldsValue());
    }
  };

  // 可选:监听字段变化,实时校验对应区块
  const handleValuesChange = (changedValues) => {
    // 判断变化的字段所属区块
    const changedFieldKey = Object.keys(changedValues)[0];
    if (changedFieldKey.startsWith('firstSection')) {
      validateSection('firstSection', [
        ["firstSection", "name"],
        ["firstSection", "phoneNumber"],
        ["firstSection", "fax"],
        ["firstSection", "address"],
        ["firstSection", "country"]
      ]);
    } else if (changedFieldKey.startsWith('secondSection')) {
      validateSection('secondSection', [["secondSection", "city"]]);
    }
  };

  return (
    <Form
      form={form}
      onValuesChange={handleValuesChange} // 开启实时校验的话需要这个
      layout="vertical"
    >
      {/* 第一区块 */}
      <div style={{ marginBottom: 24 }}>
        <h3 style={{ marginBottom: 16 }}>
          第一区块
          {/* 显示区块统一错误提示 */}
          {sectionErrors.firstSection && (
            <span style={{ color: '#ff4d4f', marginLeft: 8, fontSize: 14 }}>
              请完善本区块所有必填内容
            </span>
          )}
        </h3>
        <Form.Item
          name={["firstSection", "name"]}
          rules={[{ required: isRequired, message: "" }]} // 留空字段级错误提示
        >
          <Input placeholder="姓名" />
        </Form.Item>
        <Form.Item
          name={["firstSection", "phoneNumber"]}
          rules={[{ required: isRequired, message: "" }]}
        >
          <Input placeholder="手机号" />
        </Form.Item>
        <Form.Item
          name={["firstSection", "fax"]}
          rules={[{ required: isRequired, message: "" }]}
        >
          <Input placeholder="传真号" />
        </Form.Item>
        <Form.Item
          name={["firstSection", "address"]}
          rules={[{ required: isRequired, message: "" }]}
        >
          <Input placeholder="地址" />
        </Form.Item>
        <Form.Item
          name={["firstSection", "country"]}
          rules={[{ required: isRequired, message: "" }]}
        >
          <Input placeholder="国家" />
        </Form.Item>
      </div>

      {/* 第二区块 */}
      <div style={{ marginBottom: 24 }}>
        <h3 style={{ marginBottom: 16 }}>
          第二区块
          {sectionErrors.secondSection && (
            <span style={{ color: '#ff4d4f', marginLeft: 8, fontSize: 14 }}>
              请完善本区块所有必填内容
            </span>
          )}
        </h3>
        <Form.Item
          name={["secondSection", "city"]}
          rules={[{ required: isRequired, message: "" }]}
        >
          <Input placeholder="城市" />
        </Form.Item>
      </div>

      <Button type="primary" onClick={handleSubmit}>提交表单</Button>
    </Form>
  );
};

export default SectionedForm;

关键细节说明

  1. 隐藏字段级错误:把每个Form.Itemrules里的message设为空字符串,这样字段下面就不会显示默认的错误提示了。
  2. 批量校验APIform.validateFields(fieldList)可以只校验指定的字段数组,精准控制区块内的校验范围。
  3. 实时校验可选:如果不需要用户一输入就校验区块,可以去掉onValuesChange监听,只在提交前调用validateSection即可,这样性能更好。
  4. 错误状态维护:用useState维护每个区块的错误状态,方便在标题处根据状态显示对应的提示文本。

这个方案完全基于Antd表单的内置能力,比手动维护每个字段的错误标记要简洁可靠得多,你可以根据自己的需求调整提示文本或者校验时机~

备注:内容来源于stack exchange,提问作者Tzachi

火山引擎 最新活动