React(hook)基于antd Table实现可拖拽调整列宽的表格

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的宽度,其他有列宽的需要同等缩小
  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值