虚拟滚动是最有效、最通用的长列表性能解法,通过仅渲染可视区域及缓冲项并用 translateY 模拟位置,将 DOM 控制在几十个以内;固定高度用索引+偏移计算,动态高度需缓存高度+二分查找;需节流滚动、批量 DOM 操作、加缓冲区、复用节点及骨架占位。

直接渲染上万条数据的列表,浏览器会创建海量 DOM 节点,导致内存飙升、滚动卡顿、重排重绘频繁。虚拟滚动不渲染全部内容,只保留当前可视区域及少量缓冲项,用位置偏移模拟完整列表,从而把 DOM 数量控制在几十个以内——这是最有效、最通用的长列表性能解法。
固定高度场景:计算索引 + translateY 偏移
适用于聊天记录、日志列表、标准表格等每行高度一致的情况。核心是用滚动位置反推应显示哪几项,并整体位移对齐视觉。
- 给外层容器设固定高和
overflow-y: auto,内部用一个撑高元素(如height: totalItemCount * itemHeight)维持滚动条 - 监听
scroll事件,读取scrollTop和容器clientHeight - 算出起始索引:
startIndex = Math.floor(scrollTop / itemHeight) - 算出渲染数量:
visibleCount = Math.ceil(clientHeight / itemHeight) + buffer(如+4) - 截取数据:
data.slice(startIndex, startIndex + visibleCount) - 用
transform: translateY(${startIndex * itemHeight}px)整体下移,让内容“出现在正确位置”
动态高度支持:缓存高度 + 二分查找定位
当列表项高度不一(如富文本、多图卡片),无法用简单除法算索引。必须提前或运行时记录每项真实高度。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 首次渲染或数据加载后,遍历测量每项实际高度,存入
Map或数组:heights[i] = el.scrollHeight - 构建前缀和数组:
offsets[i]表示第i项顶部距列表起点的累计高度 - 滚动时,对
offsets数组做二分查找,快速定位scrollTop对应的startIndex - 再向后累加高度,直到凑够可视区域所需高度,确定
endIndex - 渲染时仍用
translateY,偏移量为offsets[startIndex]
滚动监听优化:避免频繁触发与布局抖动
原生 scroll 事件每帧可能触发多次,直接渲染易造成性能波动。需轻量、稳定地响应滚动。
立即学习“Java免费学习笔记(深入)”;
- 用
requestIdleCallback或debounce(延迟 8–16ms)节流,确保渲染不抢占主线程 - 绝对避免在循环中设置内联样式(如
el.style.top = xxx),改用 CSS 变量或transform - 批量操作 DOM:用
DocumentFragment拼装完再一次性挂载,减少重排 - 给占位区域设固定
height或用空div预留空间,防止图片/异步内容加载引发布局位移
进阶细节:缓冲区、复用与骨架占位
光靠“只渲染可见项”还不够,真实项目还需应对边界情况和用户体验细节。
- 上下各加 3–5 项缓冲区,避免快速滚动时出现白屏或闪烁
- DOM 复用:维护一个元素池,滚动时只更新内容和 key,不反复创建销毁节点
- 配合骨架屏(skeleton):首屏或加载新块时,先渲染灰色占位,保持高度一致
- 若用框架(React/Vue/Solid),优先选用成熟库如
react-window、vue-virtual-scroller或@solidjs/virtual,它们已内置高度缓存、复用、ResizeObserver 等能力


















