Antd实现expandable一键展开隐藏

1,328 阅读2分钟

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;