react-resizable实现antd Table组件拖动改变列宽

本文介绍如何结合react-resizable库,实现在antd Table组件中通过拖动来动态改变列宽的功能。详细阐述了集成过程和关键代码实现,为react.js前端开发者提供了一种灵活调整表格布局的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import { Table } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import { Resizable } from 'react-resizable';
import './style.css';

const ResizeableTitle = (props: any) => {
  const { onResize, width, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  return (
    <Resizable
      width={width}
      height={0}
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

const ResizeTable: React.FC<any> = (props: any) => {

  const { columns, dataSource, ...rest} = props;

  const [cols, setCols] = useState<any>(props.columns);
  const colsRef = useRef<any[]>([]);


  const components = {
    header: {
      cell: ResizeableTitle,
    },
  };  

  useEffect(() => {
    setCols(props.columns);
  }, [props.columns])
  
  const handleResize = (index: any) => (e: any, { size }: any) => {
    const nextColumns = [...cols];

    nextColumns[index] = {
      ...nextColumns[index],
      width: size.width,
    };

    setCols(nextColumns);
  };

  colsRef.current = (cols || []).map((col: any, index: any) => ({
    ...col,
    onHeaderCell: (column: any) => ({
      width: column.width,
      onResize: handleResize(index),
    }),
  }))

  return (
    <div className="components-table-resizable-column">
      <Table 
        components={components}
        columns={colsRef.current}
        dataSource={props.dataSource}
      />
    </div>
  )
}

export default ResizeTable;
/* 内容过多以...显示 */
.ellipsisText {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
}
/* 显示拖拽样式 */
.components-table-resizable-column .react-resizable {
    position: relative ;
    background-clip: padding-box;
}
.components-table-resizable-column .react-resizable-handle {
    position: absolute;
    width: 10px;
    height: 100%;
    bottom: 0;
    right: -9px;
    cursor: col-resize;
    z-index: 1;
    border-left: white 1px solid;
}
<think>好的,我需要帮助用户解决如何将react-window与Ant Design Table结合使用的问题。用户已经提到他们希望实现虚拟表,并且参考了之前的引用内容,涉及react-resizablereact-drag-listview的功能。我需要综合这些信息,给出一个清晰的示例和步骤。 首先,我应该回顾用户提供的引用内容。引用[1]提到了使用react-resizablereact-drag-listview来调整表格和拖拽位置。引用[2]给出了Ant Design Table如何通过CSS和类名来实现拖拽的样式调整。引用[3]比较了react-table的优势,但用户这里需要的是与Ant Design Table的结合。引用[4]介绍了使用react-draggable和react-resizable来调整Modal,这可能对处理表格的拖拽有参考价值。 用户的主要问题是如何将react-window与Ant Design Table结合,实现虚拟滚动,同时支持调整和拖拽顺序。Ant Design Table本身并不支持虚拟滚动,因此需要借助react-window的虚拟表来优化性能。 接下来,我需要考虑如何结构这个解决方案。可能需要使用react-window的组件(如FixedSizeList或VariableSizeList)来包裹Ant Design Table的行,实现按需渲染。同时,需要整合react-resizablereact-drag-listview来实现的调整和拖拽。 可能的步骤包括: 1. 自定义Ant Table的body部分,使用react-window的List组件来渲染可见行。 2. 处理的拖拽和调整度,可能需要修改的定义,添加相应的拖拽和调整手柄。 3. 状态管理,保存调整后的和顺序,以便在重新渲染时保持状态。 4. 样式调整,确保拖拽和调整时的视觉效果正确。 需要注意的问题包括:如何正确计算每行的度和高度,如何处理滚动事件与Ant Table的交互,以及如何保持性能优化。此外,用户可能需要动态加载数据,结合无限滚动等功能,但根据当前问题,重点是在现有数据下实现虚拟滚动和操作。 最后,我需要确保示例代码正确,并且解释清晰,让用户能够理解每一步的目的和实现方法。同时,参考之前的引用内容,特别是引用[1]和[2]中的实现方式,确保给出的方案与用户的需求一致。</think>以下是基于 Ant Design Tablereact-window 的深度整合实现方案,包含虚拟滚动、调整、拖拽三大核心功能: --- ### 一、技术栈整合原理 1. **虚拟滚动核心**:用 `react-window` 的 `FixedSizeList` 接管 Antd Table 的渲染流程 2. **调整**:通过 `react-resizable` 实现可拖拽表头 3. **拖拽**:通过 `react-draggable` 实现顺序交换 4. **状态保持**:使用 `useMemo` 缓存配置,通过 `localStorage` 持久化存储[^2][^4] --- ### 二、完整实现代码 ```jsx import { Table } from 'antd'; import { FixedSizeList as List } from 'react-window'; import { Resizable } from 'react-resizable'; import { Draggable } from 'react-draggable'; // 自定义可拖拽表头 const ResizableTitle = (props) => { const { onResize, width, ...restProps } = props; return ( <Resizable width={width} height={0} handle={ <span className="react-resizable-handle" onClick={(e) => e.stopPropagation()} /> } onResize={onResize} draggableOpts={{ enableUserSelectHack: false }} > <Draggable axis="x" onStop={(e, data) => handleColumnDrag(data.x, restProps.dataIndex)} > <th {...restProps} /> </Draggable> </Resizable> ); }; // 虚拟滚动表格体 const VirtualTableBody = ({ columns, data }) => { const Row = ({ index, style }) => ( <div style={style}> <tr> {columns.map((col) => ( <td key={col.dataIndex} style={{ width: col.width }}> {data[index][col.dataIndex]} </td> ))} </tr> </div> ); return ( <List height={500} itemCount={data.length} itemSize={54} width="100%" > {Row} </List> ); }; // 主组件 const VirtualTable = () => { const [columns, setColumns] = useState(initialColumns); const [data] = useState(generateData(10000)); // 调整处理 const handleResize = (index) => (e, { size }) => { const newColumns = [...columns]; newColumns[index] = { ...newColumns[index], width: size.width }; setColumns(newColumns); }; // 拖拽处理 const handleColumnDrag = (deltaX, dataIndex) => { const currentIndex = columns.findIndex(c => c.dataIndex === dataIndex); const targetIndex = calculateNewIndex(deltaX, currentIndex); const newColumns = [...columns]; const [moved] = newColumns.splice(currentIndex, 1); newColumns.splice(targetIndex, 0, moved); setColumns(newColumns); }; // 配置可拖拽头 const mergedColumns = columns.map((col, index) => ({ ...col, onHeaderCell: (column) => ({ width: column.width, onResize: handleResize(index), dataIndex: column.dataIndex }) })); return ( <Table bordered columns={mergedColumns} dataSource={data} components={{ header: { cell: ResizableTitle }, body: VirtualTableBody }} pagination={false} scroll={{ y: 500 }} /> ); }; ``` --- ### 三、关键配置说明 1. **性能优化**: ```jsx // 使用 CSS 关闭 Antd 默认动画 .virtual-table .ant-table-tbody { animation: none !important; } ``` 2. **状态持久化**: ```jsx // 通过 useEffect 自动保存配置 useEffect(() => { localStorage.setItem('tableColumns', JSON.stringify(columns)); }, [columns]); ``` 3. **动态加载**(结合 `react-window-infinite-loader`): ```jsx const loadMoreItems = () => { // 加载下一页数据 }; <InfiniteLoader isItemLoaded={index => index < data.length} itemCount={data.length + 1} loadMoreItems={loadMoreItems} > {/* 嵌入 VirtualTableBody */} </InfiniteLoader> ``` --- ### 四、已知问题解决方案 1. **对齐偏移**:通过 `transform: translateX()` 修正拖拽后的位置偏差 2. **滚动抖动**:设置 `overscanCount={5}` 提前预渲染缓冲行[^3] 3. **拖拽边界**:使用 `react-draggable` 的 `bounds` 属性限制拖拽范围[^4] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值