React基于antd Table实现可拖拽调整列宽的表格
前言
在日常的工作开发中,会经常的用到表格,进行数据展示,但是数据的长度不一,初始设置的表格列宽不一定符合数据的展示要求,故有时需要手动的进行表格列宽的调整。
用过antd的童鞋,都知道antd的表格并不支持列拖拽功能;那么在react+antd的项目中如何实现可拖动表格呢?
实现功能
1:表格列宽初始自动分配、列宽总和不能超过容器宽度(无横向滚动条,公司项目特殊需求)
2:当容器宽度变化时,保持当前列宽的分配比例,等比缩小
3:拖动过程中不进行列宽的调整,只有释放之后再进行列宽调整
代码实现
拖拽功能实现基础:react-resizable
- 目录结构:
- useTableCol.tsx: 处理表格列的宽度计算等相关逻辑
import { useMemoizedFn, useSafeState } from 'ahooks';
import type { ColumnType } from 'antd/es/table/interface';
import { useEffect, useRef, useCallback } from 'react';
const useTableCol = (wrapperWidth: number | undefined, columns: ColumnType<any>[]) => {
const [isInit, setInit] = useSafeState<boolean>(false);
// 保存每一列宽度的百分比,用来当容器的宽度变化时,计算每列的宽度
const titleWidthMapRef = useRef<{ titleWidthMap: Record<string, number> | undefined }>({ titleWidthMap: undefined });
// 每一列的宽度转换成数字之后的列配置
const [tableShowColumns, setTableShowColumns] = useSafeState<ColumnType<any>[]>([]);
// 初始时,将传入的表格配置数据进行转换
// 将百分比、字符串格式的宽度配置转换成对应的数字宽度
// 并根据容器的宽度做自适应
const getTableNumberWidthCol = useMemoizedFn(() => {
let resultTableColumesList: ColumnType<any>[] = [];
if (wrapperWidth && columns) {
// TODO: 筛选出所有显示的列
const showCols = columns.filter((col) => col);
const newColumesList = showCols.map((col) => {
const { width } = col;
const newCol = { ...col };
// 当配置了width属性,且width为字符串类型时,计算具体的宽度值
if (width && typeof width === 'string') {
newCol.width = width.endsWith('%') ? (wrapperWidth * parseFloat(width)) / 100 : parseFloat(width);
}
return newCol;
});
// 表格总的宽度
const totalWidth = newColumesList
.filter((item) => typeof item.width === 'number')
.reduce((sum, current) => sum + Number(current.width), 0);
// 查找出未配置宽度的列
const noWidthColumes = newColumesList.filter((col) => !col.width);
// 如果存在未配置宽度的列,则将容器未分配的宽度,等分给未分配宽度的列
if (noWidthColumes.length > 0) {
const otherWidth = wrapperWidth - totalWidth;
if (otherWidth > 0) {
// 为了简单,向下取整,并将差值放到最后一列
const commonWidth = Math.floor(otherWidth / noWidthColumes.length);
const resultColumes = newColumesList.map((col) => {
if (!col.width) {
// 最后一个未配置宽度的列宽取差值
if (col.title === noWidthColumes[noWidthColumes.length - 1].title) {
col.width = otherWidth - commonWidth * (noWidthColumes.length - 1);
} else {
// 非最后一个未配置宽度的列,则取均值的向下取整值
col.width = commonWidth;
}
}
return col;
});
resultTableColumesList = resultColumes;
} else {
// 存在未分配宽度的列,但是列的已分配宽度大于容器宽度,此处正常情况下不应出现
// 若出现了此情况,则给无列宽的列都分配60px的宽度,其他有列宽的需要同等缩小