虚拟滚动核心是仅渲染可视区域节点以减少dom数量。通过固定容器高度、用占位div撑满总高度、动态计算并渲染可见数据片段三步实现,需注意高度固定、滚动节流及缓冲区管理。

虚拟滚动核心原理:只渲染可视区域的节点
长列表卡顿本质是DOM节点过多,浏览器重排重绘压力大。虚拟滚动不真实创建全部节点,而是计算当前滚动位置对应的“可见数据片段”,仅渲染这部分(比如10~30个),其余用空白占位元素撑开滚动高度。滚动时动态更新渲染范围,视觉上无缝,实际DOM始终极少。
关键三步:容器、占位、动态渲染
1. 固定容器高度 + overflow-y: auto
外层容器必须有明确高度(不能由内容撑开),否则无法计算滚动比例和可视区域起始索引。
2. 用一个 div 撑满总高度
该 div 高度 = 单项高度 × 总数据条数,作为滚动容器的“内容区”,不放真实子项,只起占位作用。
3. 动态定位并替换可视区域节点
监听 scroll 事件或使用 IntersectionObserver,根据 scrollTop 计算当前应显示的 startIndex 和 endIndex;用 slice 截取对应数据,用绝对定位或 transform translateY 将这批节点精准摆到可视区域内。
避免常见陷阱:尺寸、缓存与性能边界
单项高度必须固定或可预估——若每行高度不同,需提前缓存各 item 高度(如 Map
滚动监听要做节流或使用 passive: true——避免频繁触发重计算;现代方案推荐用 requestIdleCallback 或 IntersectionObserver 替代直接监听 scroll。
首次渲染前先估算可视区数量——例如容器高 600px,单项高 40px → 最多渲染 15~20 项,预留缓冲区(+5 上下各)共维持约 30 个节点,超出即卸载。
轻量实现参考(无框架版思路)
不用第三方库也能快速落地:
- 维护 state:scrollTop、visibleStart、visibleEnd、itemHeight、listData
- 滚动时用 Math.floor(scrollTop / itemHeight) 得到起始索引
- 用 transform: translateY(${startIndex * itemHeight}px) 定位渲染区块
- key 保持稳定(用 index 或唯一 id),避免 React/Vue 误更新











