当前位置: 首页 > article >正文

Antd+React+react-resizable实现表格拖拽功能

1、先看效果

2、环境准备

在package.json 引入相关的依赖

  "dependencies": {
    "antd": "^5.4.0",
    "react-resizable": "^3.0.4",

  },
  "devDependencies": {
    "@types/react": "^18.0.33",
    "@types/react-resizable": "^3.0.1",
  }

3、功能实现

一、拖拽组件实现

1、导入所需组件:在你的代码文件中导入所需的组件:

import { Resizable, ResizableProps } from 'react-resizable';

 2、创建可调整大小的列组件:为了实现表格拖拽功能,你需要为每一列创建一个可调整大小的组件。在每个表格列的头部,使用Resizable组件来包裹列的内容:

/**
 * 公共组件:实现拖拽
 */
import { isNumber } from 'lodash';
import { StyleHTMLAttributes } from 'react';
import { Resizable, ResizableProps } from 'react-resizable';

type ResizableTitleProps = ResizableProps & {
  resizable?: boolean;
  style: StyleHTMLAttributes<any>;
};

const ResizableTitle = (props: ResizableTitleProps) => {
  const { onResize, width, resizable, ...restProps } = props;
  if (!width || !resizable) {
    return <th {...restProps} />;
  }
  let resizeWidth: any = width;
  if (!isNumber(resizeWidth)) {
    resizeWidth = Number(resizeWidth.replace('px', ''));
  }

  return (
    <Resizable
      width={resizeWidth}
      height={0}
      handle={
        <span
          className="react-resizable-handle"
          onClick={(e) => {
            e.stopPropagation();
          }}
        />
      }
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: true }}
      // maxConstraints={[800, 800]}
    >
      <th
        {...restProps}
        style={{
          ...restProps?.style,
          width: `${resizeWidth}px`,
          borderRight: '1px solid rgba(2, 9, 23, 70%)',
        }}
      />
    </Resizable>
  );
};

export default ResizableTitle;

 在上面的代码中,我们使用Resizable组件来包裹了列的内容。handle属性定义了列的调整大小的手柄样式,你可以根据需要自定义。draggableOpts属性用于配置调整大小的选项。

 二、在antd写入tab,并引用该拖拽组件

1、在table的components属性中,引入该拖拽组件

 <Table
   ...
      {...(isResizable
        ? {
            components: {
              header: {
                cell: ResizableTitle, // 动态拖拽设置列宽
              },
            },
          }
        : {})}
      columns={getColumns(currentColumns)}
      {...props}
    />

 2、对每一列的onHeaderCell都加上拖拽的属性resizable,控制该列是否可拖拽,配置onResize的回调方法

  const getColumns = (columns: any) => {
    return (columns || []).map((col: any, idx: number) => {
      return {
        ...col,
        onHeaderCell: (column: any) => ({
          width: column.width || 100,
          resizable: isResizable && !column?.fixed,
          onResize: handleResize(idx, col.dataIndex as string),
        }),
      };
    });
  };

 3、拖拽后更新表格的列宽

// 拖拽后更新表格宽度
  const handleResize =
    (index: number, colDataIndex?: string) =>
    (e: any, { size }: { size: { width: number } }) => {
      if (!colDataIndex) {
        return;
      }
      setCurrentColumns((pre) => {
        let temp = [...pre];
        temp[index] = {
           ...temp[index],
          width: size.width < 50 ? 50 : size.width,
         };
        computedWidth(temp);
        return temp;
      });
    };

 4、具体实现如下:

import { Table } from 'antd';
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import ResizableTitle from './ResizableTitle';
import styles from './index.less';

export interface ListTableProps {
  className?: any;
  rowClassName?: any;
  dimension?: number;
  columns?: any;
  dataSource?: any;
  pagination?: any;
  scroll?: object;
  virtual?: boolean;
  rowKey?: any;
  isShowScrollX?: boolean;
  vid?: string;
  isResizable?: boolean; //是否可退拽
  onChange?: (pagination: any, filters: any, sorter: any) => void;
}

// 暂无数据组件
const NoDataComponent = () => {
  return (
    <div className={clsx(['h-[250px]', 'flex justify-center items-center'])}>
      <div
        className={clsx([
          'w-[76px] h-[94px]',
          'bg-[url("/images/no-data.svg")] bg-no-repeat',
        ])}
      />
    </div>
  );
};

const ListTable: React.FC<ListTableProps> = ({
  className,
  rowClassName = () => '',
  onChange,
  dataSource,
  isShowScrollX,
  defaultFixedNode,
  columns: initCols,
  isResizable,
  vid = 'resize_table',
  ...props
}) => {
  const [currentColumns, setCurrentColumns] = useState([]);
  const [leftRightNodeIsFixed, setLeftRightNodeIsFixe] =
    useState(defaultFixedNode); // 左右节点是否固定

  useEffect(() => {
    setCurrentColumns(initCols);
  }, [initCols]);

  useEffect(() => {
    setCurrentColumns(initCols);
  }, [initCols]);

// 计算宽度,当出现底部滚动条时,最左最右节点固定
  const computedWidth = (columns: any) => {
    const widthAll =
      document.getElementsByClassName('ant-table-body')?.[0]?.clientWidth;
    const currentTabWidth = (columns || []).reduce((pre: number, cur: any) => {
      return Number(pre) + (Number(cur?.width) || 0);
    }, 0);
    setLeftRightNodeIsFixe(currentTabWidth > widthAll);
  };
// 拖拽后更新表格宽度
  const handleResize =
    (index: number, colDataIndex?: string) =>
    (e: any, { size }: { size: { width: number } }) => {
      if (!colDataIndex) {
        return;
      }
      setCurrentColumns((pre) => {
        let temp = [...pre];
     
        temp[index] = {
           ...temp[index],
          width: size.width < 50 ? 50 : size.width,
         };
        computedWidth(temp);
        return temp;
      });
    };

  const getColumns = (columns: any) => {
    return (columns || []).map((col: any, idx: number) => {
      return {
        ...col,
        onHeaderCell: (column: any) => ({
          width: column.width || 100,
          resizable: isResizable && !column?.fixed,
          onResize: handleResize(idx, col.dataIndex as string),
        }),
      };
    });
  };

  return (
    <Table
      rowClassName={(record, index) => {
        return rowClassName(record, index);
      }}
      locale={{ emptyText: <NoDataComponent /> }}
      {...(isResizable
        ? {
            components: {
              header: {
                cell: ResizableTitle, // 动态拖拽设置列宽
              },
            },
          }
        : {})}
      columns={getColumns(currentColumns)}
      onChange={onChange}
      dataSource={dataSource}
      {...props}
    />
  );
};

export default ListTable;

4、常见问题:

1、拖拽时,鼠标离开,拖拽被还原,80%原因是因为父组件触发了useState更新,column被还原成初始态,

2、拖拽要设置最小宽度和最大宽度,防止拖拽过程中找不到元素


http://www.kler.cn/a/232392.html

相关文章:

  • github和Visual Studio
  • 《动手学深度学习》中d2l库的安装以及问题解决
  • python selenium库的使用:通过兴趣点获取坐标
  • 【Java Web】Ajax 介绍及 jQuery 实现
  • Unity教程(十八)战斗系统 攻击逻辑
  • 相机光学(四十)——2x2 Adjacent Pixel Binning
  • 代码随想录算法训练营DAY16 | 二叉树 (3)
  • 机器学习——有监督学习和无监督学习
  • SQL注入 - 利用报错函数 floor 带回回显
  • flask+vue+python跨区通勤人员健康体检预约管理系统
  • C++ 调用lua 脚本
  • Ubuntu 1804 And Above Coredump Settings
  • re:从0开始的CSS学习之路 6. 字体相关属性
  • NLP自然语言处理
  • 【Java EE】----SpringBoot的日志文件
  • Window环境下使用go编译grpc最新教程
  • Text2SQL研究-Chat2DB体验与剖析
  • Kubernetes CNI Calico:Route Reflector 模式(RR) calico IPIP切换RR网络模式
  • 年假作业day2
  • Vue中路由守卫的详细应用
  • yo!这里是Linux线程保姆级入门介绍
  • vue百度地图的和element输入框/v-region的联动
  • springboo冬奥会科普平台源码和论文
  • D7 Elasticsearch-Mongodb(搜索记录)
  • flutter 国内源
  • python-分享篇-画樱花