Antd实现expandable一键展开隐藏
今天我们来实现一个对 antd 的 Table 中可展开列进行一键展开/隐藏的功能,这个功能 antd 的 Table 中并没有进行实现,但是可能我们会有这样的需求,比如我今天就遇到了。于是就自己写一个吧。
大概效果是这样的:
主要是利用 Table 组件中提供的 expandable 配置来实现。通常情况下,我们不配置其中的 expandedRowKeys 配置就已经可以实现 Table 行中的单行的展开和隐藏了,但是如果我们要进行一键展开的话,自然 expandedRowKeys 需要由我们自己来进行控制,所以核心无非就是怎么去控制 expandedRowKeys。
我们起两个 state,expandedRowKeys 用于保存展开的 key,expandButtonStatus 用于保存当前是全展开 \ 全隐藏,同时也利用这个状态来控制 expandedRowKeys 的清空与否。
handleClickExpandButton 方法就是根据expandButtonStatus 状态清空expandedRowKeys 和添加全部的 key,这里需要特别注意的就是 key 一定要是 string 类型的,antd 的文档写的很清楚,其他类型是没有效果的哈!你可以用模版字符串也可以用 String 包一下,也可以 tostring,总之 string 类型
可以一键展开隐藏,当然也需要可以单个隐藏和展开。接下来重点关注下 expandable 配置,配置项附带有注释,这里提一下这个 key 一定要注意保证是 string 类型才会生效,然后所用的字段不一定必须是 key,返回的数据中有 id 等唯一字段也是可以的,只要你和rowKey={(record) => String(record.key)}这里设置的 rowKey 可以对应即可
expandable={{
columnTitle: '详细信息', // 表头
expandedRowKeys: expandedRowKeys, //收控制的keys数组
expandedRowRender: (record) => ( // 展开的信息,一个函数,返回你需要展示的内容
<p style={{ margin: 0 }}>{record.description}</p>
),
expandIcon: ({ expanded, onExpand, record }) =>
expanded ? (
// 如果已经展开,显示隐藏图标,回调事件:将本行的key从keys数组中移除
<MinusCircleTwoTone
onClick={(e) => {
setExpandedRowKeys((prev) => {
return prev.filter((item) => item !== `${record.key}`);
});
}}
/>
) : (
// 如果已经隐藏,显示展开图标,回调事件:如果expandedRowKeys数组中已经包含本key了则不添加,否则将key添加进入keys数组中
<PlusCircleTwoTone
onClick={(e) => {
setExpandedRowKeys((prev) => {
if (prev.includes(`${record.key}`)) {
return prev;
} else {
return [...prev, `${record.key}`];
}
});
}}
/>
),
}}
最后的话补充一点,这里代码没有写,因为一般 Table 可能会带有翻页和搜索等,这时候如果页面是全展开或者部分展开的情况显示效果可能不佳,所以我们可以监听一下 data 的改变,改变后就刷新一下expandedRowKeys 的状态。
类似这种:
// .... 在翻页事件中改变page触发fetchData -> data改变
// .... 在搜索事件中改变搜索参数触发fetchData -> data改变
useEffect(() => {
setExpandedRowKeys([])
setExpandButtonStatus(false)
}, [data]);
完整的代码如下:
import React, { useEffect, useState } from 'react';
import 'antd/dist/antd.css';
import './index.css';
import { Table, Button } from 'antd';
import { PlusCircleTwoTone, MinusCircleTwoTone } from '@ant-design/icons';
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
{
title: 'Action',
dataIndex: '',
key: 'x',
render: () => <a>Delete</a>,
},
];
const data = [
{
key: 1,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
description:
'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description:
'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Not Expandable',
age: 29,
address: 'Jiangsu No. 1 Lake Park',
description: 'This not expandable',
},
{
key: 4,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
description:
'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
},
];
const App = () => {
const [expandedRowKeys, setExpandedRowKeys] = useState([]);
const [expandButtonStatus, setExpandButtonStatus] = useState(false);
const handleClickExpandButton = () => {
if (expandButtonStatus) {
setExpandedRowKeys([]);
setExpandButtonStatus(false);
} else {
setExpandedRowKeys(data.map((it) => `${it.key}`));
setExpandButtonStatus(true);
}
};
useEffect(() => {
console.log(expandedRowKeys);
}, [expandedRowKeys]);
return (
<Table
columns={columns}
rowKey={(record) => String(record.key)}
title={() => (
<Button
style={{ marginTop: 10 }}
onClick={handleClickExpandButton}
type="primary"
>
{expandButtonStatus ? '隐藏' : '展开'}
</Button>
)}
expandable={{
columnTitle: '详细信息',
expandedRowKeys: expandedRowKeys,
expandedRowRender: (record) => (
<p style={{ margin: 0 }}>{record.description}</p>
),
expandIcon: ({ expanded, onExpand, record }) =>
expanded ? (
<MinusCircleTwoTone
onClick={(e) => {
setExpandedRowKeys((prev) => {
return prev.filter((item) => item !== `${record.key}`);
});
}}
/>
) : (
<PlusCircleTwoTone
onClick={(e) => {
setExpandedRowKeys((prev) => {
if (prev.includes(`${record.key}`)) {
return prev;
} else {
return [...prev, `${record.key}`];
}
});
}}
/>
),
}}
dataSource={data}
/>
);
};
export default App;