0%

react-ant-design-component-table-6

今天我们继续讲解Ant Design中的Table组件,今天的主题是如何为Table组件添加操作功能,这里的操作是针对每一行数据而言的,比如我们可以编辑、删除某一行数据,或者查看某一行数据的详情等。

要实现这些操作,我们需要在Table组件的列定义中添加一个操作列(操作列通常位于最后一列),这个操作列通常会包含一些按钮或者菜单,用户可以通过点击这些按钮或菜单来执行相应的操作。

因为操作列并不是数据(Table组件中的dataSource)的一部分,所以这一列并不需要dataIndex属性,我们可以直接在columns数组的末尾添加一个新的列对象,设置其title为“操作”,并使用render渲染具体的操作内容,比如编辑和删除按钮。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const columns = [
// ...
{
title: '操作',
key: 'action',
render: (_: any, record: User) => (
<span>
<a onClick={() => console.log('Edit', record)}>编辑</a>
<span style={{ margin: '0 8px' }}>|</span>
<a onClick={() => console.log('Delete', record)}>删除</a>
</span>
),
},
];

有的时候,因为render函数对应的代码比较多,我们可以单独将其提取出来,作为一个单独的函数来处理,这样可以使代码更清晰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const renderActions = (record: User) => (
<span>
<a onClick={() => console.log('Edit', record)}>编辑</a>
<span style={{ margin: '0 8px' }}>|</span>
<a onClick={() => console.log('Delete', record)}>删除</a>
</span>
);

const columns = [
// ...
{
title: '操作',
key: 'action',
render: renderActions,
},
];

我们向render函数传入了当前行的数据(record),这样我们就可以在操作中使用这行数据了,上面例子中,我们只是简单地打印了编辑和删除的记录,但在实际应用中,我们可能会调用后台api来执行编辑或删除操作。

由于已经拿到了当前行数据record,所以我们也可以拿到这行数据对应的id,有了id,我们就可以在点击编辑或删除按钮时,将id传递给相应的后台API来做真实的编辑和删除操作了。

最后,我们看一下render函数的定义,它接收三个参数,分别是:

  • value: 当前单元格的值
  • record: 当前行的数据记录
  • index: 当前行的索引
    在我们的例子中,我们并没有使用valueindex,但它们在某些情况下可能会有用,比如当你需要根据行索引来处理某些逻辑时。
1
render?: (value: any, record: RecordType, index: number) => React.ReactNode | RenderedCell<RecordType>;

render函数的返回值可以是一个React节点(比如一个按钮或链接),也可以是一个自定义的渲染组件。目前我们用到的都是第一种情况,返回一个React节点。

下面我们以编辑和删除为例,看看如何通过Actions列处理这两种操作。

定义Action列

首先,我们在Action列中定义两个按钮:编辑和删除,当用户点击这两个按钮时,分别执行对应的操作。为了显示美观,我们使用Space组件来排列这两个按钮。Space组件会自动在两个组件之间加上间距。

1
2
3
4
5
6
7
8
const renderAction = (value: any, record: User) => {
return (
<Space>
<Button type='link' onClick={() => onEditButtonClick(record)}>编辑</Button>
<Button type='link' onClick={() => onDeleteButtonClick(record)}>删除</Button>
</Space>
)
}

删除操作

这里使用onDeleteButtonClick函数来处理删除操作。删除操作是一个比较敏感的操作,通常来说,在执行删除操作之前,我们需要弹出一个确认对话框,询问用户是否真的要删除这个记录。也就是要给用户一个二次确认的机会。这里我们使用Ant Design的Modal组件来实现这个功能。

1
2
3
4
5
6
7
8
9
10
11
12
const onDeleteButtonClick = (record: User) => {
Modal.confirm({
title: '确认删除',
content: `您确定要删除用户 ${record.name} 吗?`,
onOk: () => {
handleDelete(record.id);
},
onCancel: () => {
console.log('Delete cancelled');
},
})
}

只有当用户点击了Modal上的“删除”按钮时,才会真正执行删除操作。

调用API删除数据

1
2
3
4
5
6
7
8
9
10
const handleDelete = async (userId: number) => {
try {
// 调用后端API删除用户
await deleteUser(userId);
// 删除成功后重新获取用户列表
getUsers(pageNumber, pageSize);
} catch (error) {
console.error('Error deleting user:', error);
}
}

删除的操作就比较简单了,我们调用后端API deleteUser,传入用户的ID,然后在删除成功后重新获取用户列表。

编辑操作

编辑操作一般通过弹窗的形式来实现,在Ant Design中,弹窗就是Modal组件。我们可以在点击编辑按钮时,弹出一个Modal,里面包含一个表单,用户可以在这个表单中修改用户信息。

定义编辑Modal

首先定义这个Modal的属性,注意:Modal的打开和关闭需要父控件来控制,所以我们传入一个变量isVisible来控制Modal的显示和隐藏。另外,我们还需要传入一个userId来表示当前编辑的用户ID(用来获取用户详情并显示在Modal上),以及两个回调函数onOKonCancel,分别在编辑成功或者取消编辑时调用。

1
2
3
4
5
6
type UserEditModalProps = {
isVisible: boolean; // 控制Modal的打开和关闭
userId: number | null; // 当前编辑的用户ID
onOK: () => void;
onCancel: () => void;
}

紧接着定义Modal组件,组件的命名规则一般是:业务名称 + 操作名称 + 组件类型,所以我们这里就命名为UserEditModal

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
export default function UserEditModal(props: UserEditModalProps) {
const [form] = Form.useForm();
const { isVisible, userId, onOK, onCancel } = props;

return (
<Modal
title="编辑用户"
open={isVisible}
okText={'保存'}
onOk={onOkButtonClick}
onCancel={onCancel}
cancelText={'取消'}
>
<Form form={form} layout="vertical">
<Form.Item
name="name"
label="姓名"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input placeholder="请输入姓名" />
</Form.Item>
<Form.Item
name="email"
label="邮箱"
rules={[{ required: true, message: '请输入邮箱' }]}
>
<Input placeholder="请输入邮箱" />
</Form.Item>
{/* 可以添加更多表单项 */}
</Form>
</Modal>
)
}

因为我们这里使用了Form组件,所以需要先创建一个form实例,这个实例会被传递给Modal中的Form组件。接下来,我们需要在Modal中添加表单项,比如姓名和邮箱等。

接下来我们通过传入的userId来获取用户详情,并将其设置到表单中,这样用户在编辑时就可以看到当前用户的信息了。

1
2
3
4
5
6
useEffect(() => {
if (isVisible && userId) {
// 这里可以添加获取用户信息的逻辑
getUserInfo(userId);
}
}, [isVisible, userId]);

这里需要注意的是,Ant Design的Modal组件无论打开还是关闭,都会渲染到页面上,为了避免在Modal打开之前就调用API,我们这里加了isVisible的判断,只有当Modal是可见的,并且userId存在时,才会调用getUserInfo函数来获取用户信息。

当成功获取用户信息后,通过form.setFieldsValue将这些信息显示到页面上。

1
2
3
4
const getUserInfo = async (userId: number) => {
const userDetail = await getUserDetail(userId);
form.setFieldsValue(userDetail);
}

接下来就是编辑操作了,当用户点击Modal的保存按钮时,我们需要验证表单数据是否有效,如果有效,就调用API来保存用户信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const submitForm = async (values: any) => {
// 调用API保存用户信息
const res = await submitUser(values);
if (res.success) {
onOK(); // 调用父组件的 onOK 方法,关闭Modal
} else {
console.error('保存失败:', res.message);
}
}

const onOkButtonClick = () => {
// 验证表单数据
form.validateFields().then(values => {
submitForm(values)
}).catch(error => {
console.error('表单验证失败:', error);
});
}

如果表单数据验证失败,比如某些必填项没有填写,或者格式不正确,validateFields会抛出一个错误,Ant Design也会在页面上给出相应的提示。

完整代码如下:

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
export default function UserEditModal(props: UserEditModalProps) {
const [form] = Form.useForm();
const { isVisible, userId, onOK, onCancel } = props;

const getUserInfo = async (userId: number) => {
const userDetail = await getUserDetail(userId);
form.setFieldsValue(userDetail);
}

const submitForm = async (values: any) => {
const res = await submitUser(values);
if (res.success) {
onOK(); // 调用父组件的 onOK 方法,关闭Modal
} else {
// 处理错误
console.error('保存失败:', res.message);
}
}

const onOkButtonClick = () => {
form.validateFields().then(values => {
// 这里可以添加保存用户信息的逻辑
submitForm(values)
})
}

useEffect(() => {
if (isVisible && userId) {
getUserInfo(userId);
}
}, [isVisible, userId]);

return (
<Modal
title="编辑用户"
open={isVisible}
okText={'保存'}
onOk={onOkButtonClick}
onCancel={onCancel}
cancelText={'取消'}
>
<Form form={form} layout="vertical">
<Form.Item
name="name"
label="姓名"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input placeholder="请输入姓名" />
</Form.Item>
<Form.Item
name="email"
label="邮箱"
rules={[{ required: true, message: '请输入邮箱' }]}
>
<Input placeholder="请输入邮箱" />
</Form.Item>
</Form>
</Modal>
)
}

好了,今天就到这里了,我们明天再见!