You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为带自定义组件的Ant Design Table添加虚拟滚动?

可行解决方案:保留自定义行组件的Ant Design Table虚拟滚动实现

针对你的需求,推荐两种可复用且兼容性好的方案,均能保留components.body.row自定义行组件(比如右键菜单)的功能:


方案一:基于react-window+自定义tbody容器(适配固定行高)

通过替换Antd Table的tbody为虚拟滚动容器,同时完全复用你的自定义行组件,避免布局破坏。

步骤1:依赖安装

npm install react-window react-virtualized-auto-sizer

步骤2:封装虚拟表格组件

import React, { useMemo, useRef } from 'react';
import { Table } from 'antd';
import AutoSizer from 'react-virtualized-auto-sizer';
import { List } from 'react-window';

const VirtualTable = ({ columns, data, rowHeight = 50, components, ...restProps }) => {
  const { body: originalBodyComponents } = components || {};
  // 保留你自定义的行组件
  const CustomRow = originalBodyComponents?.row || 'tr';

  // 自定义虚拟滚动tbody容器
  const VirtualBodyWrapper = ({ ...rest }) => {
    return (
      <AutoSizer>
        {({ height }) => (
          <List
            height={height}
            itemCount={data.length}
            itemSize={rowHeight}
            width="100%"
          >
            {({ index, style }) => {
              const record = data[index];
              // 传递所有行组件需要的props,包括自定义事件(如右键菜单)
              return (
                <CustomRow
                  {...rest}
                  style={{ ...style, position: 'absolute' }}
                  record={record}
                  index={index}
                  key={record.key || index}
                />
              );
            }}
          </List>
        )}
      </AutoSizer>
    );
  };

  // 合并自定义组件与虚拟滚动容器
  const modifiedComponents = useMemo(() => ({
    ...components,
    body: {
      ...originalBodyComponents,
      wrapper: VirtualBodyWrapper,
    },
  }), [components, originalBodyComponents]);

  return (
    <div style={{ position: 'relative' }}>
      <Table
        columns={columns}
        dataSource={data}
        components={modifiedComponents}
        scroll={{ y: 'auto' }}
        pagination={false}
        {...restProps}
      />
    </div>
  );
};

export default VirtualTable;

步骤3:使用虚拟表格(保留自定义右键菜单行)

import VirtualTable from './VirtualTable';

// 你的自定义行组件(带右键菜单)
const CustomRowWithMenu = ({ record, index, ...rest }) => {
  const handleContextMenu = (e) => {
    e.preventDefault();
    // 这里写你的右键菜单逻辑
    console.log('触发右键菜单:', record);
  };

  return <tr {...rest} onContextMenu={handleContextMenu} />;
};

// 业务组件中使用
const App = () => {
  const columns = [
    { title: 'ID', dataIndex: 'id', key: 'id' },
    { title: '名称', dataIndex: 'name', key: 'name' },
    // 你的其他列配置
  ];
  const largeData = Array.from({ length: 1000 }).map((_, i) => ({
    id: i + 1,
    name: `条目${i + 1}`,
    key: `${i + 1}`
  }));

  return (
    <VirtualTable
      columns={columns}
      data={largeData}
      rowHeight={55} // 根据你的行高调整
      components={{
        body: {
          row: CustomRowWithMenu,
        },
      }}
    />
  );
};

方案二:基于Antd官方依赖rc-virtual-list(更贴近Antd原生实现)

Antd内部虚拟滚动逻辑基于rc-virtual-list,直接扩展该组件可实现更好的兼容性,同样保留自定义行组件。

步骤1:依赖安装

npm install rc-virtual-list

步骤2:封装虚拟表格组件

import React from 'react';
import { Table } from 'antd';
import VirtualList from 'rc-virtual-list';

const VirtualTable = ({ columns, data, rowHeight = 50, components, height = 500, ...rest }) => {
  const { body: originalBody } = components || {};
  const CustomRow = originalBody?.row || 'tr';

  const VirtualBodyWrapper = ({ ...wrapperProps }) => {
    return (
      <VirtualList
        dataSource={data}
        height={height}
        itemHeight={rowHeight}
        itemKey={(item) => item.key}
      >
        {(item, index) => (
          <CustomRow
            {...wrapperProps}
            record={item}
            index={index}
            key={item.key}
          >
            {/* 渲染列内容,完全复用Antd列配置 */}
            {columns.map(col => (
              <td key={col.key}>{col.render?.(item) || item[col.dataIndex]}</td>
            ))}
          </CustomRow>
        )}
      </VirtualList>
    );
  };

  return (
    <Table
      columns={columns}
      dataSource={data}
      components={{
        ...components,
        body: {
          ...originalBody,
          wrapper: VirtualBodyWrapper,
        },
      }}
      pagination={false}
      {...rest}
    />
  );
};

export default VirtualTable;

关键注意事项

  1. 行高设置:固定行高是虚拟滚动性能最优的方案,如果需要动态行高,可替换react-window的List为VariableSizeList,或rc-virtual-list开启动态行高配置(需提前计算行高)。
  2. 事件绑定:确保自定义行组件接收并传递所有props(如style、record等),避免右键菜单等事件失效。
  3. 布局兼容:外层容器设置position: relative,确保虚拟滚动的行元素定位正确。

内容的提问来源于stack exchange,提问作者Luxaaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 00:51:20