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

如何为Antd Table实现虚拟横向滚动以解决多列性能问题?

为Antd Table实现横向虚拟滚动的方案

核心思路

Antd Table原生仅支持垂直虚拟滚动,要实现横向虚拟滚动,核心是只渲染可视区域内的列:通过计算列宽与滚动偏移量,动态控制列的显隐,同时模拟匹配真实列总宽度的横向滚动效果。

具体实现步骤

1. 封装列处理逻辑

  • 提前定义或一次性计算所有列的宽度,维护一个列宽数组columnWidths。
  • 监听表格外层容器的横向滚动事件,获取滚动偏移量scrollLeft。
  • 计算可视列范围:
    • 累加列宽,找到第一个累加宽度大于scrollLeft的列作为起始列。
    • 继续累加至宽度超过scrollLeft + 容器可视宽度,得到结束列。
    • 从原始列数组中截取[startIndex, endIndex]范围内的列,作为当前渲染列。

2. 表头与表体同步对齐

  • 将列处理逻辑封装为自定义Hook(如useVirtualColumns),让表头和表体共用同一套计算结果,保证滚动时列对齐。

3. 模拟真实滚动范围

  • 在表格外层创建一个宽度等于所有列总宽度的占位元素,让滚动条长度匹配真实列总宽度,触发正常的横向滚动行为。示例代码:
import { Table } from 'antd';
import { throttle } from 'lodash';

const VirtualTable = ({ columns, data, scrollY = 600 }) => {
  const [visibleColumns, setVisibleColumns] = useState([]);
  const [totalWidth, setTotalWidth] = useState(0);
  const containerRef = useRef(null);

  // 初始化计算列宽与总宽度
  useEffect(() => {
    const widths = columns.map(col => col.width || 120);
    const sum = widths.reduce((acc, curr) => acc + curr, 0);
    setTotalWidth(sum);
    // 初始渲染可视列
    updateVisibleColumns(0, containerRef.current?.clientWidth || 0);
  }, [columns]);

  // 节流处理滚动事件
  const handleScroll = throttle((e) => {
    const { scrollLeft, clientWidth } = e.target;
    updateVisibleColumns(scrollLeft, clientWidth);
  }, 16);

  // 更新可视列
  const updateVisibleColumns = (scrollLeft, clientWidth) => {
    let currentWidth = 0;
    let startIndex = 0;
    // 找到起始列
    while (startIndex < columns.length && currentWidth <= scrollLeft) {
      currentWidth += columns[startIndex].width || 120;
      startIndex++;
    }
    startIndex = Math.max(0, startIndex - 1);

    currentWidth = 0;
    let endIndex = startIndex;
    // 找到结束列
    while (endIndex < columns.length && currentWidth <= scrollLeft + clientWidth) {
      currentWidth += columns[endIndex].width || 120;
      endIndex++;
    }

    setVisibleColumns(columns.slice(startIndex, endIndex));
  };

  return (
    <div ref={containerRef} style={{ overflowX: 'auto' }} onScroll={handleScroll}>
      {/* 占位容器,提供真实滚动宽度 */}
      <div style={{ width: totalWidth, visibility: 'hidden', height: 0 }} />
      <Table
        columns={visibleColumns}
        dataSource={data}
        scroll={{ y: scrollY }}
        pagination={false}
      />
    </div>
  );
};

4. 固定列适配(可选)

如果存在固定列,需将固定列从虚拟滚动逻辑中剥离,单独渲染;计算可视列时,要扣除固定列的宽度,避免偏移量计算错误。

注意事项

  • 优先使用固定列宽,避免动态计算带来的性能损耗;若需动态计算,建议在组件初始化时完成。
  • 滚动事件必须节流,避免频繁触发列计算导致卡顿。
  • 严格保证表头与数据单元格的宽度一致,防止出现对齐错乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:57:13