虚拟滚动通过只渲染可视区域及缓冲区行数(如25行)并用translatey偏移定位,配合spacer占位撑起滚动条,解决大数据表格dom过多导致的卡顿问题。

JavaScript 中大数据表格渲染卡顿,核心问题不是数据多,而是浏览器被迫创建并维护海量 DOM 节点。虚拟滚动不加载全部数据,只渲染“眼睛正在看”的那几十行,再配合位置偏移和高度占位,就能让上万行表格滚动如丝般顺滑。
只渲染可视区域 + 缓冲区
假设表格容器高 500px,每行固定高 40px,那么最多同时显示约 13 行(500 ÷ 40 ≈ 12.5 → 向上取整)。虚拟滚动就只生成这 13 行 DOM,外加上下各 3–5 行缓冲,总共渲染不到 25 行——哪怕原始数据有 5 万条,DOM 节点也始终控制在个位数数量级。
关键操作:
- 监听容器的 scroll 事件,实时读取
scrollTop - 计算起始索引:
startIndex = Math.floor(scrollTop / itemHeight) - 计算结束索引:
endIndex = Math.min(startIndex + visibleCount + buffer, data.length) - 用
data.slice(startIndex, endIndex)截取待渲染子集
用 translateY 精准对齐视觉位置
只渲染部分数据会导致内容“跳到顶部”,必须把这小段列表整体向下挪动,让它看起来像是从第 1000 行开始的。这个偏移量就是 startIndex × itemHeight。
推荐写法:
- 给实际渲染的容器(如
<div class="content">)设置 <code>style.transform = 'translateY(' + (startIndex * itemHeight) + 'px)' - 避免用
top或margin-top,transform 更高效且不触发重排 - 容器需设
position: relative或absolute,确保 transform 生效 - 创建一个空的
<div class="spacer">,插入滚动容器内部最上方或最下方<li>设其高度为:<code>data.length * itemHeight - 该元素不参与渲染、不绑定事件、不设内容,纯 CSS 占位
- 这样滚动条比例、拖拽手感、滚动到底部的判断都完全真实
-
动态行高:提前缓存每行真实高度(例如用 Map 存
index → height),滚动时用二分查找快速定位startIndex -
滚动节流:用
requestAnimationFrame包裹渲染逻辑,避免连续触发导致丢帧 -
首屏优化:初始不等 scroll 触发,直接按
scrollTop = 0渲染前 N 行,用户打开即见内容 -
键盘导航支持:监听
ArrowDown/PageDown等事件,手动更新scrollTop并触发重绘
撑起滚动条:靠占位容器模拟总高度
滚动条长度由容器的 scrollHeight 决定。如果只渲染 20 行,scrollHeight 就只有 800px,根本拉不到底部。必须用一个不可见的“撑高层”告诉浏览器:“这其实是个 5 万行的表”。
实现方式:
进阶优化点(真实项目必备)
固定高度只是起点。生产环境还需应对这些情况:











