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

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 (<Resizablewidth={resizeWidth}height={0}handle={<spanclassName="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'])}><divclassName={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 (<TablerowClassName={(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、拖拽要设置最小宽度和最大宽度,防止拖拽过程中找不到元素

相关文章:

  • 通过docker-compose部署NGINX服务,并使该服务开机自启
  • DQN的理论研究回顾
  • nvm安装node后,npm无效
  • vue - 指令(一)
  • 在 CentOS 7上使用 Apache 和 mod_wsgi 部署 Django 应用的方法
  • ‘javax.sql.DataSource‘ that could not be found的问题
  • 什么是冒烟测试,UT测试,IT测试,如何来开展这些测试
  • iPhone搞机记录
  • JavaScript流程控制详解之顺序结构和选择结构
  • Spring boot集成各种数据源操作数据库
  • IP地址如何保护网络安全
  • 【Linux】生产者消费者模型
  • linux 下mongodb7版本怎么连?
  • [python] 过年燃放烟花
  • okhttp 的 拦截器
  • 分享的文章《人生如棋》
  • Flannel解读
  • interface和setter,getter
  • JavaScript DOM 10 - 滚动
  • JWT究竟是什么呢?
  • node入门
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • Vue官网教程学习过程中值得记录的一些事情
  • Vultr 教程目录
  • XForms - 更强大的Form
  • 将 Measurements 和 Units 应用到物理学
  • 开发基于以太坊智能合约的DApp
  • 如何用vue打造一个移动端音乐播放器
  • 使用API自动生成工具优化前端工作流
  • 一个SAP顾问在美国的这些年
  • 鱼骨图 - 如何绘制?
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • #QT(一种朴素的计算器实现方法)
  • $.ajax()方法详解
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (二)斐波那契Fabonacci函数
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (三)Honghu Cloud云架构一定时调度平台
  • (三)uboot源码分析
  • (十六)Flask之蓝图
  • (算法二)滑动窗口
  • (转)jQuery 基础
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • 、写入Shellcode到注册表上线
  • .Net Core和.Net Standard直观理解
  • .Net IE10 _doPostBack 未定义
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • ?.的用法
  • [100天算法】-目标和(day 79)
  • [Android 数据通信] android cmwap接入点
  • [Android] Android ActivityManager