如何为带自定义组件的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;
关键注意事项
- 行高设置:固定行高是虚拟滚动性能最优的方案,如果需要动态行高,可替换
react-window的List为VariableSizeList,或rc-virtual-list开启动态行高配置(需提前计算行高)。 - 事件绑定:确保自定义行组件接收并传递所有props(如
style、record等),避免右键菜单等事件失效。 - 布局兼容:外层容器设置
position: relative,确保虚拟滚动的行元素定位正确。
内容的提问来源于stack exchange,提问作者Luxaaa
相关产品推荐
相关产品推荐

