React Antd Form.List使用教程
Form.List 是 Ant Design (antd) 中用于动态管理表单字段的组件,特别适合处理数组类型的表单数据。它的核心是通过函数式渲染(render props)的方式,将字段列表和操作方法暴露给开发者。以下是 Form.List 组件中各个参数的详细解释。
Form.List 的基本结构
<Form.List name="字段名">
{(fields, operations, meta) => ReactNode}
</Form.List>
name:字段名,用于标识表单数据中的数组字段。children:一个函数,接收三个参数:fields、operations和meta,返回 React 节点。
1. fields 参数
fields 是一个数组,包含了当前 Form.List 中所有的动态字段。每个字段是一个对象,包含以下属性:
字段对象的属性:
-
key:string- 每个字段的唯一标识符,用于 React 的
key属性。
- 每个字段的唯一标识符,用于 React 的
-
name:number- 字段在数组中的索引(从 0 开始)。
-
fieldKey:number- 与
name相同,用于兼容旧版本。
- 与
-
isListField:boolean- 标识该字段是否属于
Form.List,通常为true。
- 标识该字段是否属于
fields.map(({ key, name, fieldKey, ...restField }) => (
<Form.Item key={key} name={[name, 'fieldName']}>
<Input />
</Form.Item>
));
2. operations 参数
operations 是一个对象,包含用于操作字段的方法:
方法:
-
add:(defaultValue?: any, insertIndex?: number) => void-
添加一个新字段。
-
参数:
defaultValue:可选,新字段的默认值。insertIndex:可选,插入字段的位置(从 0 开始)。如果不传,默认添加到末尾。
add({ fieldName: '默认值' }, 0); // 在索引 0 处插入一个新字段 -
-
move:(from: number, to: number) => void- 将一个字段从
from索引移动到to索引。
move(0, 1); // 将索引 0 的字段移动到索引 1 - 将一个字段从
-
remove:(index: number | number[]) => void-
删除一个或多个字段。
-
参数:
index:要删除的字段的索引(从 0 开始),可以是一个索引或索引数组。
remove(0); // 删除索引为 0 的字段 remove([0, 1]); // 删除索引为 0 和 1 的字段 -
3. meta 参数
meta 是一个对象,包含当前 Form.List 的元信息:
属性:
-
errors:ReactNode[]- 当前
Form.List中所有字段的验证错误信息。
- 当前
-
warnings:ReactNode[]- 当前
Form.List中所有字段的验证警告信息。
- 当前
{meta.errors.length > 0 && (
<div style={{ color: 'red' }}>{meta.errors.join(', ')}</div>
)}
4. name 属性
name 是 Form.List 的一个必需属性,用于标识表单数据中的数组字段。
<Form.List name="tasks">
{(fields) => fields.map(({ key, name }) => (
<Form.Item key={key} name={[name, 'taskName']}>
<Input />
</Form.Item>
))}
</Form.List>
- 在这个示例中,
name="tasks"表示表单数据中的tasks字段是一个数组。 - 每个字段的
name属性需要设置为[name, 'fieldName'],其中name是字段的索引,fieldName是字段的名称。
5. 完整示例
以下是一个完整的示例,展示了 Form.List 的用法:
import { Form, Input, Button, Space } from 'antd';
const NestedFormList = () => {
const onFinish = (values) => {
console.log('Received values of form:', values);
};
return (
<Form onFinish={onFinish}>
{/* 外层:项目列表 */}
<Form.List name="projects">
{(projects, { add: addProject, remove: removeProject }) => (
<>
{projects.map(({ key: projectKey, name: projectName }) => (
<div key={projectKey} style={{ marginBottom: 16, border: '1px solid #ddd', padding: 16 }}>
<Form.Item
{...projects[projectName]}
name={[projectName, 'projectName']}
label="项目名称"
rules={[{ required: true, message: '请输入项目名称' }]}
>
<Input placeholder="项目名称" />
</Form.Item>
{/* 中层:任务列表 */}
<Form.List name={[projectName, 'tasks']}>
{(tasks, { add: addTask, remove: removeTask }) => (
<>
{tasks.map(({ key: taskKey, name: taskName }) => (
<div key={taskKey} style={{ marginBottom: 16, padding: 8, border: '1px solid #eee' }}>
<Form.Item
{...tasks[taskName]}
name={[taskName, 'taskName']}
label="任务名称"
rules={[{ required: true, message: '请输入任务名称' }]}
>
<Input placeholder="任务名称" />
</Form.Item>
{/* 内层:子任务列表 */}
<Form.List name={[taskName, 'subTasks']}>
{(subTasks, { add: addSubTask, remove: removeSubTask }) => (
<>
{subTasks.map(({ key: subTaskKey, name: subTaskName }) => (
<div key={subTaskKey} style={{ marginBottom: 8 }}>
<Form.Item
{...subTasks[subTaskName]}
name={[subTaskName, 'subTaskName']}
label="子任务名称"
rules={[{ required: true, message: '请输入子任务名称' }]}
>
<Input placeholder="子任务名称" />
</Form.Item>
<Button type="link" onClick={() => removeSubTask(subTaskName)}>
删除子任务
</Button>
</div>
))}
<Button type="dashed" onClick={() => addSubTask()} block>
添加子任务
</Button>
</>
)}
</Form.List>
<Button type="link" onClick={() => removeTask(taskName)}>
删除任务
</Button>
</div>
))}
<Button type="dashed" onClick={() => addTask()} block>
添加任务
</Button>
</>
)}
</Form.List>
<Button type="link" onClick={() => removeProject(projectName)}>
删除项目
</Button>
</div>
))}
<Button type="dashed" onClick={() => addProject()} block>
添加项目
</Button>
</>
)}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
提交
</Button>
</Form.Item>
</Form>
);
};
export default NestedFormList;
注意事项
name路径:在嵌套的Form.List中,name属性需要正确设置路径(如[name, 'fieldName'])。- 字段索引:
fields中的name是字段的索引(从 0 开始),用于绑定表单数据。 - 动态操作:
add和remove方法用于动态添加或删除字段,move用于调整字段顺序