网站首页 > 开源技术 正文
表格 Table 要展示统计行应该是个很常见的业务需求,本文将介绍一种实现此功能的方法。注意,此方法不兼容 IE 浏览器。
场景介绍
公司存量项目使用的 antd 版本为 3.x,此版本的 antd 并没有支持统计行功能,只有一个 footer 属性可以在表格底部增加一行内容,但是这个并不能满足统计行的要求(无论是单元格对齐还是横向滚动),所以需要想个其他方法去实现统计行。
同时对于公司内新项目来说,用的是 antd 5.x 的版本,此版本支持统计行功能,但是需要使用 Summary 组件去构造统计行,功能灵活但是使用上会麻烦些。
所以就思考有没有能在不同 antd 版本下都实现统计行的技术方案,同时使用上又比较简单。
实现方案
首先来分析下统计行的特点:
- 统计行是独立的一行数据,会使当前页的数据量 +1,如一页 10 条数据的话,加上统计行则为 11 条。
- 通常表格竖向滚动时,统计行会固定在表格尾部。
- 样式和交互需要和表格为一个整体,包括单元格、横向滚动等等。
对于第一点,如果 antd 的 Table 组件设置了分页功能,比如 pagination: { pageSize: 10 },此时就无法展示额外的统计行,所以我们不使用 Table 的分页功能,自己通过组合 Pagination 组件来实现分页,数据传参方面, Table 的 dataSource 除了当前页数据,在拼上统计行数据即可。
第二点,固定在尾部,对于现代 css 来说,直接使用 position: sticky 实现即可。
第三点的话,在第一点提到的方案中已经实现。
整体来说,就是实现以下两个功能点:
- 不使用 Table 内置的分页,使用 Table 和 Pagination 组合来完成。
- 使用 position: sticky 完成固定行能力。
具体实现
在 antd Table API 基础上,新增一个 summaryFixed API,代表统计行(即最后一行)固定在表格底部,默认为 false,不影响没有统计行的列表展示。
首先我们实现下统计行固定功能。
import React from "react";
import classNames from "classnames";
import { Table as AntdTable } from "antd";
import "./table.css";
export default function Table({
summaryFixed,
...restProp
}) {
return (
<div
className={classNames("my-enhance-table", {
"my-enhance-table-summary-fixed": summaryFixed,
})}
>
<AntdTable {...restProp} />
</div>
);
}
代码中使用到了 classnames 库,在 summaryFixed 为 true 的时候,就会加上对应类名,接着就根据 my-enhance-table-summary-fixed 类名设置对应 css。
.my-enhance-table.my-enhance-table-summary-fixed {
tr.ant-table-row:last-child {
background: #fff;
position: sticky; /* 设置为 sticky 布局 */
bottom: 0; /* 固定在底部 */
z-index: 2;
&:not(:first-child) > td {
border-top: 1px solid #f0f0f0;
}
}
tr.ant-table-row:nth-last-child(2) {
> td {
border-bottom: 0;
}
}
}
上述 css 中通过 tr.ant-table-row:last-child 选择器选中最后一行并设置为 sticky 布局,其他 css 代码是处理边框问题的。
固定统计行功能实现完成后,接着通过组合 Table 和 Pagination 组件的方式实现统计行的展示。
import React, { useRef, useEffect } from "react";
import isEmpty from "lodash/isEmpty";
import classNames from "classnames";
import { Table as AntdTable, Pagination } from "antd";
import "./table.css";
export default function Table({
dataSource,
columns,
pagination,
onChange,
summaryFixed,
...restProp
}) {
const onTableChange = (pagination, filters, sorter, extra) => {
// 处理排序和筛选之类功能
};
const onPaginationChange = (current, pageSize) => {
// 处理翻页功能
};
return (
<div
className={classNames("my-enhance-table", {
"my-enhance-table-summary-fixed": summaryFixed,
})}
>
<AntdTable
{...restProp}
pagination={false}
dataSource={dataSource}
columns={columns}
onChange={onTableChange}
/>
{pagination !== false && (
<Pagination {...pagination} onChange={onPaginationChange} />
)}
</div>
);
}
将 Table 的 pagination 设置为 false,并将外部的 pagination 参数传给传入到 Pagination 组件,我们就可以在 pageSize 为 10 的情况下,让 dataSource 内容全部展示(即使 dataSource 的数据量超过 10)。
最后我们需要处理下翻页和排序等相关操作:
...
const initPagination = { current: 1, pageSize: 10, total: 0 };
// 获取 columns 中排序参数,区分首次和后续更新
const getSorterParam = (columns, isInit = false) => {
const sorterParam = {};
for (let index = 0; index < columns.length; index++) {
const { sorter, defaultSortOrder, sortOrder, dataIndex, key } =
columns[index] || {};
const order = isInit
? sortOrder != null
? sortOrder
: defaultSortOrder
: sortOrder;
if (sorter && order) {
sorterParam.field = dataIndex || key;
sorterParam.columnKey = dataIndex || key;
sorterParam.order = order;
sorterParam.column = columns[index];
return sorterParam;
}
}
return sorterParam;
};
export default function Table({
dataSource,
columns,
pagination,
onChange,
summaryFixed,
...restProp
}) {
const sorterParam = useRef(getSorterParam(columns, true));
const filtersParam = useRef({});
const paginationParam = useRef(pagination || initPagination);
useEffect(() => {
paginationParam.current = pagination || initPagination;
}, [pagination]);
useEffect(() => {
// 排序可控模式下更新排序
if (columns.some((col) => !!col.sortOrder)) {
sorterParam.current = getSorterParam(columns);
}
}, [columns]);
const onTableChange = (pagination, filters, sorter, extra) => {
if (!isEmpty(sorter)) {
sorterParam.current = sorter;
}
if (!isEmpty(filters)) {
filtersParam.current = filters;
}
if (onChange) {
onChange(
isEmpty(pagination) ? paginationParam.current : pagination,
filtersParam.current,
sorterParam.current,
extra
);
}
};
const onPaginationChange = (current, pageSize) => {
paginationParam.current = { ...paginationParam.current, current, pageSize };
pagination?.onChange?.(current, pageSize);
onTableChange(paginationParam.current, undefined, undefined, {
currentDataSource: dataSource,
action: "paginate",
});
};
return (
...
)
}
无论是翻页还是排序或筛选,我们都需要记录下对应的值。因为翻页功能是单独的 Pagination 组件提供的,所以触发翻页时,我们需要用到之前的排序或筛选参数,通过 onChange 一起给到外部;触发排序或筛选的情况同理,需要用到最近一次的翻页参数。
最终完整代码可查看:https://codesandbox.io/p/sandbox/antd-table-tong-ji-xing-gu-ding-grlz88?file=%2FTable.js%3A19%2C27
总结
通过组合 Pagination 组件来实现超过当前每页条数的数据量展示,同时配合现代 css 的 position: sticky 能力,我们实现了让 Table 表格支持统计行功能。当然,上述代码有需要优化的地方,比如翻页后回到表格顶部等等。
猜你喜欢
- 2024-10-13 自己手写一个SpringMVC框架(springmvc框架搭建流程)
- 2024-10-13 Restyle 来了!下一代 React 组件的样式技术
- 2024-10-13 向工程腐化开炮 | proguard治理(向僵尸开炮工程师雇佣兵怎么得到)
- 2024-10-13 Spring Boot 之 spring.factories
- 2024-10-13 前端开发React18 - 组件(react 组件设计)
- 2024-10-13 Android 混淆那些事儿(android混淆后怎么反编译)
- 2024-10-13 Spring源码分析(四)——Bean定义阶段细节之bean名称的生成策略
- 2024-10-13 值得推荐的5种 瀑布流场景的实现原理解析
- 2024-10-13 微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI
- 2024-10-13 实时目标检测神器:YOLOv5的安装与使用详解
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)