WinddSnow

Ant-Design-Advanced-Components-ProTable-ProForm

字数统计: 4.4k阅读时长: 20 min
2026/07/29

第40课:Ant Design 高级组件——ProTable、ProForm

Ant Design 的标准组件已经覆盖了大部分 UI 需求,但在企业级后台场景中,表格和表单往往需要查询筛选分页加载行内编辑批量操作等复合功能。Ant Design Pro 组件库(@ant-design/pro-components)在标准组件之上封装了两大核心组件:ProTable——将表格、查询表单、分页、工具栏融为一体的“超级表格”;ProForm——将表单布局、验证、提交、数据转换整合为声明式 JSON 配置的“智能表单”。本节课将分别深入这两个组件的核心 API 和实战模式。


1. ProTable:集查询、表格、分页于一体的超级组件

ProTable 解决的核心痛点是:每个列表页都要重复实现“查询表单 + 表格 + 分页”的组合逻辑。它将这三者封装为一个组件,通过声明列的 valueTyperequest 函数,只需少量代码即可完成一个完整的列表页。

1.1 安装 Pro Components

1
pnpm add @ant-design/pro-components

@ant-design/pro-components 是一个整合包,包含了 ProTable、ProForm、ProLayout 等全部 Pro 组件。也可以按需单独安装 @ant-design/pro-table@ant-design/pro-form

1.2 基础 ProTable:一个请求函数 + 列定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import React from 'react';
import { ProTable } from '@ant-design/pro-components';

const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
valueType: 'digit',
},
{
title: '城市',
dataIndex: 'city',
key: 'city',
valueType: 'select',
valueEnum: {
beijing: { text: '北京' },
shanghai: { text: '上海' },
guangzhou: { text: '广州' },
},
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
valueType: 'dateTime',
hideInSearch: true, // 在查询表单中隐藏此列
},
];

function UserList() {
return (
<ProTable
columns={columns}
request={async (params) => {
// params 包含查询表单的值、分页参数 { current, pageSize }
console.log('请求参数:', params);
// 模拟 API 调用
const mockData = [
{ id: 1, name: '张三', age: 28, city: 'beijing', createdAt: '2026-04-01' },
{ id: 2, name: '李四', age: 32, city: 'shanghai', createdAt: '2026-04-02' },
];
return {
data: mockData,
success: true,
total: 2,
};
}}
rowKey="id"
search={{ labelWidth: 'auto' }}
pagination={{ pageSize: 10 }}
/>
);
}

export default UserList;

核心 API 解析

属性 / 概念 说明
columns 列定义数组。与 Ant Design Tablecolumns 完全兼容,但 ProTable 增加了 valueTypevalueEnumhideInSearch 等 Pro 专属属性。
request ProTable 的核心。一个异步函数,接收 params(包含分页、排序、查询表单数据),必须返回 { data, success, total } 格式。
valueType 声明列的数据类型,ProTable 据此自动生成查询表单项和表格渲染格式。内置类型包括 textdigitdateselectmoney 等 20+ 种。
valueEnum 枚举值映射,配合 valueType: 'select' 使用,自动生成下拉筛选器和表格中的标签渲染。格式为 { key: { text: '显示文字' } }{ key: { text: '文字', status: 'Success' } }(status 会生成彩色标签)。
hideInSearch 在自动生成的查询表单中隐藏该列(仅表格可见,不参与搜索)。
hideInTable 在表格中隐藏该列(仅查询表单可见,如纯搜索字段)。
search 查询表单配置:labelWidth 设置标签宽度,span 设置每行表单项数量,defaultCollapsed 是否默认收起。
pagination 分页配置,与 Ant Design Tablepagination 一致。
toolBarRender 自定义工具栏渲染函数,通常放置“新增”按钮。
rowSelection 批量选择配置,支持多选和回调。

1.3 自动生成的查询表单

ProTable 会根据 columns未设置 hideInSearch: true 的列自动生成查询表单。表单的控件类型由 valueType 决定:

valueType 生成的查询控件
text Input
digit InputNumber
select Select(选项来自 valueEnum
date DatePicker
dateTime DatePicker(showTime)
money InputNumber(带货币前缀)
textarea Input.TextArea

自定义查询表单项:如果内置的 valueType 不满足需求,可以使用 renderFormItem 自定义查询控件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: {
active: { text: '启用', status: 'Success' },
inactive: { text: '禁用', status: 'Error' },
},
// 自定义查询表单项(覆盖默认的 Select)
renderFormItem: (_, { type, defaultRender }) => {
if (type === 'form') {
return null; // 不渲染查询项
}
return defaultRender(_);
},
}

1.4 工具栏与批量操作

使用 toolBarRenderrowSelection 可实现带批量操作的列表页。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<ProTable
columns={columns}
request={fetchUsers}
rowKey="id"
rowSelection={{
onChange: (selectedRowKeys, selectedRows) => {
console.log('选中行:', selectedRowKeys, selectedRows);
},
}}
tableAlertRender={({ selectedRowKeys, onCleanSelected }) => (
<span>
已选择 {selectedRowKeys.length} 项
<a style={{ marginLeft: 8 }} onClick={onCleanSelected}>
取消选择
</a>
</span>
)}
tableAlertOptionRender={({ selectedRowKeys }) => (
<Space>
<a>批量删除</a>
<a>导出</a>
</Space>
)}
toolBarRender={() => [
<Button key="add" type="primary">新增用户</Button>,
<Button key="export">导出</Button>,
]}
/>
  • tableAlertRender:表格上方警告提示区域的内容(多选时显示)。
  • tableAlertOptionRender:批量操作按钮区域。
  • toolBarRender:表格工具栏,返回 React 元素数组。

1.5 可编辑表格(行内编辑)

ProTable 支持通过 editable 属性开启行内编辑,无需弹窗即可直接修改数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const [editableKeys, setEditableRowKeys] = useState([]);

<ProTable
columns={columns}
request={fetchUsers}
rowKey="id"
editable={{
type: 'multiple',
editableKeys,
onChange: setEditableRowKeys,
onSave: async (key, row) => {
console.log('保存行:', key, row);
// 调用 API 保存
},
onDelete: async (key, row) => {
console.log('删除行:', key, row);
},
}}
/>

editable 配置中的 type 可选 'single'(一次只能编辑一行)或 'multiple'(可同时编辑多行)。每一列可通过 editable: false 禁止编辑。


2. ProForm:声明式表单布局与验证

ProForm 在 Ant Design Form 的基础上提供了JSON 化配置网格布局查询表单模式步骤表单等高级封装。其最大的特点是:表单的布局验证提交数据转换都可以通过配置完成,减少样板代码。

2.1 基础 ProForm 与网格布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { ProForm, ProFormText, ProFormSelect, ProFormDigit } from '@ant-design/pro-components';

function CreateUserForm() {
return (
<ProForm
onFinish={async (values) => {
console.log('提交数据:', values);
// 调用 API
}}
autoFocusFirstInput
>
<ProForm.Group>
<ProFormText
name="name"
label="姓名"
placeholder="请输入姓名"
rules={[{ required: true, message: '姓名为必填项' }]}
/>
<ProFormText
name="email"
label="邮箱"
placeholder="请输入邮箱"
rules={[
{ required: true, message: '请输入邮箱' },
{ type: 'email', message: '邮箱格式不正确' },
]}
/>
</ProForm.Group>

<ProForm.Group>
<ProFormSelect
name="role"
label="角色"
valueEnum={{
admin: '管理员',
editor: '编辑者',
viewer: '观察者',
}}
placeholder="请选择角色"
rules={[{ required: true }]}
/>
<ProFormDigit
name="age"
label="年龄"
min={0}
max={150}
fieldProps={{ precision: 0 }}
/>
</ProForm.Group>
</ProForm>
);
}

核心 API

组件 / 属性 说明
ProForm 表单容器。onFinish 为提交回调(自动处理 validate)。autoFocusFirstInput 自动聚焦第一个输入框。
ProForm.Group 表单分组容器,内部子项默认水平排列(Flex 布局)。
ProFormText 文本输入框(封装 Input)。name 为字段名,label 为标签,rules 为验证规则。
ProFormSelect 下拉选择框。valueEnum 与 ProTable 的列定义一致。
ProFormDigit 数字输入框(封装 InputNumber)。min/max 控制范围。

ProForm 内置的常用字段组件

组件 对应控件 专有属性
ProFormText Input
ProFormTextArea Input.TextArea
ProFormDigit InputNumber minmaxfieldProps.precision
ProFormSelect Select valueEnumfieldProps.mode
ProFormDatePicker DatePicker
ProFormDateTimePicker DatePicker (showTime)
ProFormSwitch Switch
ProFormRadio Radio.Group options / valueEnum
ProFormCheckbox Checkbox.Group options / valueEnum
ProFormUploadButton Upload actionmax
ProFormMoney InputNumber(货币) 自动格式化货币符号
ProFormCaptcha Input + 验证码按钮 onGetCaptcha 回调

2.2 查询表单模式:searchLightFilter

ProForm 内置了查询过滤器的预设样式。设置 layout="inline" 可水平排列,也可使用 search 属性快速生成标准查询表单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ProForm
search={{
labelWidth: 'auto',
defaultCollapsed: false,
}}
onFinish={handleSearch}
>
<ProFormText name="keyword" label="关键字" />
<ProFormSelect
name="status"
label="状态"
valueEnum={{
all: '全部',
active: '启用',
inactive: '禁用',
}}
/>
</ProForm>

2.3 动态表单项与依赖联动

利用 ProFormDependency 可以根据其他字段的值动态渲染表单项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { ProForm, ProFormDependency, ProFormSelect, ProFormText } from '@ant-design/pro-components';

<ProForm>
<ProFormSelect
name="type"
label="类型"
valueEnum={{
individual: '个人',
enterprise: '企业',
}}
/>
<ProFormDependency name={['type']}>
{({ type }) => {
if (type === 'enterprise') {
return (
<ProFormText
name="companyName"
label="企业名称"
rules={[{ required: true, message: '请输入企业名称' }]}
/>
);
}
return null;
}}
</ProFormDependency>
</ProForm>

ProFormDependencyname 可以监听一个或多个字段,回调函数接收最新的字段值,根据值动态返回组件。

2.4 与 Modal 和 Drawer 的组合

ProForm 支持 modalPropsdrawerProps,可以一键将表单嵌入到模态框或抽屉中。这使得“点击按钮 → 弹出表单 → 提交数据”的流程变得极为简洁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { ProForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';

function CreateUserModal({ open, onOpenChange }) {
return (
<ProForm
onFinish={async (values) => {
console.log('创建用户:', values);
onOpenChange(false);
}}
modalProps={{
open,
onCancel: () => onOpenChange(false),
title: '新增用户',
destroyOnClose: true,
}}
>
<ProFormText name="name" label="姓名" rules={[{ required: true }]} />
<ProFormText name="email" label="邮箱" rules={[{ required: true, type: 'email' }]} />
<ProFormSelect
name="role"
label="角色"
valueEnum={{ admin: '管理员', editor: '编辑者' }}
rules={[{ required: true }]}
/>
</ProForm>
);
}

modalProps.opentrue 时,ProForm 会自动渲染为一个模态框。提交成功后,你只需在 onFinish 中调用 onOpenChange(false) 关闭弹窗。整个流程无需手动管理 Modal 的显示/隐藏状态和 Form 的交互。


3. 综合实战:用户管理页面(ProTable + ProForm Modal)

以下示例将 ProTable 和 ProForm 组合为一个完整的用户管理 CRUD 页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import React, { useRef, useState } from 'react';
import { ProTable } from '@ant-design/pro-components';
import { Button, message, Space, Tag } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import UserFormModal from './UserFormModal';

const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{
title: '角色',
dataIndex: 'role',
key: 'role',
valueType: 'select',
valueEnum: {
admin: { text: '管理员', status: 'Success' },
editor: { text: '编辑者', status: 'Processing' },
viewer: { text: '观察者', status: 'Default' },
},
},
{ title: '邮箱', dataIndex: 'email', key: 'email' },
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
valueType: 'dateTime',
hideInSearch: true,
},
{
title: '操作',
valueType: 'option',
render: (_, record) => [
<a key="edit" onClick={() => handleEdit(record)}>编辑</a>,
<a key="delete" style={{ color: 'red' }} onClick={() => handleDelete(record)}>删除</a>,
],
},
];

const mockUsers = [
{ id: 1, name: '张三', role: 'admin', email: 'zhangsan@example.com', createdAt: '2026-04-01' },
{ id: 2, name: '李四', role: 'editor', email: 'lisi@example.com', createdAt: '2026-04-02' },
{ id: 3, name: '王五', role: 'viewer', email: 'wangwu@example.com', createdAt: '2026-04-03' },
];

export default function UserManagement() {
const [users, setUsers] = useState(mockUsers);
const [modalOpen, setModalOpen] = useState(false);
const [editingUser, setEditingUser] = useState(null);
const actionRef = useRef();

const fetchUsers = async (params) => {
let filtered = [...users];
if (params.name) {
filtered = filtered.filter((u) => u.name.includes(params.name));
}
if (params.role) {
filtered = filtered.filter((u) => u.role === params.role);
}
return { data: filtered, success: true, total: filtered.length };
};

const handleAdd = () => {
setEditingUser(null);
setModalOpen(true);
};

const handleEdit = (record) => {
setEditingUser(record);
setModalOpen(true);
};

const handleDelete = (record) => {
setUsers((prev) => prev.filter((u) => u.id !== record.id));
message.success('删除成功');
actionRef.current?.reload();
};

const handleSave = (values) => {
if (editingUser) {
setUsers((prev) =>
prev.map((u) => (u.id === editingUser.id ? { ...u, ...values } : u))
);
message.success('修改成功');
} else {
const newUser = { id: Date.now(), ...values, createdAt: new Date().toISOString() };
setUsers((prev) => [...prev, newUser]);
message.success('添加成功');
}
setModalOpen(false);
actionRef.current?.reload();
};

return (
<>
<ProTable
columns={columns}
request={fetchUsers}
rowKey="id"
actionRef={actionRef}
search={{ labelWidth: 'auto' }}
toolBarRender={() => [
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
新增用户
</Button>,
]}
/>
<UserFormModal
open={modalOpen}
onOpenChange={setModalOpen}
initialValues={editingUser}
onFinish={handleSave}
/>
</>
);
}

// UserFormModal.jsx
import { ProForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';

export default function UserFormModal({ open, onOpenChange, initialValues, onFinish }) {
return (
<ProForm
onFinish={onFinish}
initialValues={initialValues}
modalProps={{
open,
onCancel: () => onOpenChange(false),
title: initialValues ? '编辑用户' : '新增用户',
destroyOnClose: true,
}}
>
<ProFormText name="name" label="姓名" rules={[{ required: true, message: '请输入姓名' }]} />
<ProFormText name="email" label="邮箱" rules={[{ required: true, type: 'email' }]} />
<ProFormSelect
name="role"
label="角色"
valueEnum={{ admin: '管理员', editor: '编辑者', viewer: '观察者' }}
rules={[{ required: true }]}
/>
</ProForm>
);
}

协同流程总结

  1. ProTable 负责列表展示、查询筛选、分页。actionRef 可用于在外部调用 reload() 刷新表格。
  2. 新增/编辑 通过独立的 UserFormModal 组件实现,该组件内部使用 ProForm 配合 modalProps 自动生成模态框。
  3. 数据流:父组件 UserManagement 管理 users 状态,ProTablerequest 基于该状态进行前端筛选;保存表单时更新状态并调用 reload()

课后练习

一、概念自测(选择题 / 填空题)

  1. (单选) ProTable 中,request 函数的返回值必须包含哪些字段?
    A. { data, total }
    B. { data, success, total }
    C. { list, success, total }
    D. { rows, total, pageSize }

  2. (单选) 在 ProTable 的列定义中,要让某列在表格中显示但在查询表单中隐藏,应设置哪个属性?
    A. hideInTable: true
    B. hideInSearch: true
    C. search: false
    D. hidden: true

  3. (填空) ProForm 中使用 ______ 组件可以根据其他字段的值动态渲染表单项,实现字段间的联动。

  4. (多选) 以下哪些是 ProForm 内置的字段组件?
    A. ProFormText
    B. ProFormSelect
    C. ProFormSlider
    D. ProFormDigit

二、AI 编程任务:编写面向 AI 的提示词

场景:你需要实现一个文章管理页面,包含以下功能:

  • 使用 ProTable 展示文章列表,列包括:标题、分类(枚举:技术/生活/随笔)、状态(已发布/草稿)、发布时间、操作列(编辑/删除按钮)。
  • 表格支持按标题模糊搜索、按分类和状态下拉筛选。
  • 点击“新建文章”或“编辑”按钮,使用 ProForm 配合 modalProps 弹出模态框表单,表单包含:标题输入框、分类选择、状态选择、内容文本域。
  • 保存时更新列表数据(可使用本地 state 模拟,无需真实 API)。
  • 删除时弹出确认提示,删除后刷新列表。

任务要求:请写出一段完整的中文提示词,发送给 AI,使其生成完整的 React 组件文件(可拆分为 2 个文件:列表页 + 表单弹窗)。提示词中需明确指定 ProTable 的列定义、查询筛选配置、ProForm 的字段与验证规则,以及新增/编辑/删除的数据流。


课后练习答案

一、概念自测答案

  1. B

    • 解析:ProTable 的 request 必须返回 { data: any[], success: boolean, total: number } 格式,缺一不可。
  2. B

    • 解析:hideInSearch: true 使列在自动生成的查询表单中不可见,但保留在表格中。hideInTable: true 则相反。
  3. ProFormDependency

    • 解析:ProFormDependency 监听一个或多个字段的值变化,回调中根据值动态渲染其他表单项。
  4. A、B、D

    • 解析:ProFormTextProFormSelectProFormDigit 均为 ProForm 内置字段组件。ProFormSlider 并非内置组件(Ant Design Pro 未提供该封装,需自行结合 SliderProForm.Item 实现)。

二、AI 编程任务参考答案(提示词示例)

示例提示词
“请生成一个使用 Ant Design Pro Components 的文章管理页面,包含列表和表单弹窗两个组件。要求:

  • 安装并使用 @ant-design/pro-components
  • **列表组件 ArticleList.jsx**:
    • 使用 ProTablerowKey="id"search={{ labelWidth: 'auto' }}
    • 列定义:title(标题,valueType: 'text')、category(分类,valueType: 'select'valueEnum: { tech: '技术', life: '生活', essay: '随笔' })、status(状态,valueType: 'select'valueEnum: { published: { text: '已发布', status: 'Success' }, draft: { text: '草稿', status: 'Default' } })、publishDate(发布时间,valueType: 'date'hideInSearch: true)、操作列(valueType: 'option',render 返回编辑和删除链接)。
    • request 函数:基于本地 useState 数组 articles 模拟数据,支持按 titleincludes 模糊匹配)、categorystatus 筛选。初始化 3 条静态数据。
    • toolBarRender 返回一个“新建文章”按钮,点击时设置 editingArticlenull 并打开弹窗。
    • actionRef 用于在外部刷新表格。
    • 编辑:点击行内编辑链接,设置 editingArticle 为当前行数据并打开弹窗。
    • 删除:点击删除链接,使用 Modal.confirm 确认后从数组中移除并 actionRef.current?.reload()
  • **表单弹窗组件 ArticleFormModal.jsx**:
    • 接收 openonOpenChangeinitialValuesonFinish 四个 Props。
    • 使用 ProFormmodalProps 绑定 openonCanceltitle(根据 initialValues 判断“新建”还是“编辑”)、destroyOnClose
    • 表单字段:titleProFormText,必填)、categoryProFormSelect,必填,valueEnum 同列表)、statusProFormSelect,必填)、contentProFormTextArea,可选)。
    • onFinish 将表单值传给父组件的保存函数。
  • 代码完整可运行,组件拆分清晰。输出两个文件的完整内容。”
CATALOG
  1. 1. 第40课:Ant Design 高级组件——ProTable、ProForm
    1. 1.1. 1. ProTable:集查询、表格、分页于一体的超级组件
      1. 1.1.1. 1.1 安装 Pro Components
      2. 1.1.2. 1.2 基础 ProTable:一个请求函数 + 列定义
      3. 1.1.3. 1.3 自动生成的查询表单
      4. 1.1.4. 1.4 工具栏与批量操作
      5. 1.1.5. 1.5 可编辑表格(行内编辑)
    2. 1.2. 2. ProForm:声明式表单布局与验证
      1. 1.2.1. 2.1 基础 ProForm 与网格布局
      2. 1.2.2. 2.2 查询表单模式:search 与 LightFilter
      3. 1.2.3. 2.3 动态表单项与依赖联动
      4. 1.2.4. 2.4 与 Modal 和 Drawer 的组合
    3. 1.3. 3. 综合实战:用户管理页面(ProTable + ProForm Modal)
    4. 1.4. 课后练习
      1. 1.4.1. 一、概念自测(选择题 / 填空题)
      2. 1.4.2. 二、AI 编程任务:编写面向 AI 的提示词
    5. 1.5. 课后练习答案
      1. 1.5.1. 一、概念自测答案
      2. 1.5.2. 二、AI 编程任务参考答案(提示词示例)