Antd表格的二次封装

515 阅读3分钟

wtcl.jpg

一、表格 Column 的数据格式

我们需要这个Column的属性来分别去渲染搜索表单和表格,这里参考了一下 proColumn 中,表格 Column 的常用属性。

  • search: 是否需要搜索,默认为true;
  • hideInTable: 是否在表格内不展示,默认为 false;
  • type: 搜索的类型,这里可以在做搜索表单时自定义,如 'date' 为日期搜索, 'select'为下拉搜索;
  • valueEnum: 下拉搜索的选项;

二、基础表格的实现

首先要明确实现什么样的功能,对于表格数据的展示来说,必不可少的就是表格列、表格的数据、是否分页、是否每行可选、表格加载数据的 loading 等等基本的功能,那同时,我们也在表格上方留出一部分作为工具区域,放置一些其他的按钮。

基于我们所需的这些基本的功能,我们就可先做出一个基本的表格来。

const {toolBar = [], optional, isCheck. ...} = props;

<div>
    {toolBar.map((item) =>
        // 暂时没考虑按钮发生改变
        React.cloneElement(item, { key: item.index, className: styles.toolButton }, item.props.children),
    )}
    <Table
        pagination={optional ? paginationProps : false}
        rowSelection={isCheck ? rowSelection : undefined}
        rowKey="id"
        ...
    />
</div>

toolBar 即上面所说到的,表格上方的工作区,optional、isCheck 分别判断是否需要分页和选中列的功能。

使用 React.cloneElement 可以对每个元素混入props,这里是加了样式让按钮之间存在距离。

三、搜索表单的实现

和表格一样,先要明确我们需要什么,对于表单来说,我们需要的就是搜索项、搜索的方法、以及根据上文提到的Column的各种属性来去渲染,另外,除了搜索和重置的功能外,再留出自定义按钮的部分。

1、根据 type 动态匹配搜索类型
const getInput = (item) => {
    switch (item.type) {
        case 'select':
            return ...;
        case 'date':
            return ...;
        default:
            return <Input placeholder="请输入" allowClear className={styles.inputWidth} />;
    }
};

这里我们用一个方法来根据 type 去动态判断他是什么类型的搜索,这里我用的 switch case,默认的情况下就是输入框即可。 至于自定义的部分,只要在查询重置按钮后面,遍历即可,这里我用的 children 来传值。

<Form form={form} layout="inline" onFinish={handleSubmit} className={styles.basicForm}>
    {searchFormList.map((item) => (
        <Form.Item name={item.dataIndex} key={item.dataIndex} label={item.title}>
            {getInput(item)}
        </Form.Item>
    ))}
    <Form.Item>
        <Button className={styles.searchButton} type="primary" htmlType="submit">
            查询
        </Button>
        <Button onClick={handleResetForm} className={styles.searchButton}>
            重置
        </Button>
        </Form.Item>
        <div className={styles.extraButton}>
            {children.map((item: any) => (
                <Form.Item key={item.index}>{item}</Form.Item>
            ))}
        </div>
</Form>

这里直接遍历父组件传来的搜索表单列表,通过判断类型的方法去进行动态渲染。

四、整合

最后我们将表单和表格整合即可,搜索表单的list我们过滤掉 search 为 false 的无需搜索项和key为'action'的操作列,表格展示过滤掉 hideInTable 属性为 true 的隐藏项。然后分别传值就好。

// 搜索项
const searchColum = colums.filter((item) => item.search !== false && item.key !== 'action');
// 展示列
const tableColum = colums.filter((item) => !item.hideInTable);

写到这里又有一个新的问题,我们没有重置页面数据的方法暴露出去,如果进行删除或者更新等操作,在外面是没办法及进行刷新的。由于这个组件使用函数式组件进行编写的,我们使用 forwardRef 搭配 useImperativeHandle 就可以暴露外部需要访问的方法。

...
// 重置页面
const resetPage = (type: 'delete' | 'update' | 'reset' = 'reset') => {
    let current = page.page; // 当前页
    switch (type) {
        // 如果是删除且是本页最后一条,则重置取上一页
        case 'delete':
            current = listData.data.length === 1 ? page.page - 1 : page.page;
            break;
        // 整体重置回到第一页
        case 'reset':
            current = 1;
            break;
        default:
            break;
    }
    changePage({ current, pageSize: page.page_size });
};

// 暴露重置页面数据方法
seImperativeHandle(ref, () => ({
    resetPage,
}));
...
export default forwardRef(BasicPage);

另外,对于自定义按钮的部分,我采用的是数组的形式来传值。

const formTool = [<Button type='primary' key="btn">自定义</Button>, ...]

最后看下大致的效果

image.png