FIXED-HEIGHT VIRTUAL SCROLL · INTERACTIVE LAB

虚拟滚动原理:固定高度交互课

以 el-select-v2 为例。十万条数据,页面上始终只有十几个 DOM —— 秘密藏在三个区域的协作里:视口区域、内容区域、占位容器。滚动下面的列表,或按下播放键,观察它们如何一起运动。

真实运行的虚拟列表

el-select-v2 风格
请选择 未选中(共 10,000 项)
VIEWPORT · 视口区域:overflow-y:auto,固定高度 300px
2

结构透视 X-RAY

同步运动
#0
#9999
占位容器 PHANTOM
虚线琥珀轨道 = 占位容器(全长 = 数据总高);蓝色框 = 视口(你正看见的窗口);绿色块 = 实际渲染的内容(视口 + 上下缓冲)。因总高与视口相差悬殊,透视元素已放大示意,运动关系完全真实。

这一帧的实时计算

scroll 驱动
scrollTop 滚动距离
0 px
总高度 n × itemH
400,000 px
startIndex 起始索引
0
endIndex 结束索引
8
translateY 内容层位移
translateY(0 px)
真实存在的 DOM 节点12 / 10,000

三个区域,各司其职

01 / LAYERS
区域一 · VIEWPORT

视口区域:取景框

一个固定高度、overflow-y:auto 的容器。它做两件事:决定一屏能看到几项;通过滚动事件把 scrollTop(滚了多远)告诉你。它是整个计算的输入。

区域二 · PHANTOM

占位容器:撑出滚动条

一个空 div,高度设为 n × itemHeight,里面一个选项都不渲染。唯一任务是"骗"浏览器:让滚动条长度和真实十万行列表一模一样。没有它就没有滚动条、没有惯性滚动。

height = n × itemHeight
区域三 · CONTENT

内容区域:真正的列表项

绝对定位的一层,里面只有"可视项 + 上下缓冲项"这十几个 DOM。用 transform:translateY() 整体下移到视口对应的位置。滚动时换数据、换位移,DOM 数量恒定。

滚动一帧,发生了什么

02 / ONE FRAME
1

捕获滚动

视口触发 scroll,拿到 scrollTop

2

算起点

start = floor(scrollTop / itemH)

3

算终点

end = start + ceil(vpH / itemH),两端加 buffer

4

切片渲染

只渲染 data.slice(start,end) 这一小段

5

整体位移

内容层 translateY(start × itemH)

6

DOM 恒定

无论滚到哪,节点数始终是十几条

为什么需要虚拟滚动

03 / COMPARE

普通全量渲染

把 10,000 个选项全部塞进 DOM
10,000 个 DOM
初次渲染要创建上万个节点,下拉打开卡顿、滚动掉帧;el-select-v2 正是为解决这个问题而生。

虚拟滚动渲染

占位容器撑高度,只渲染可视 + 缓冲
12 个 DOM
节点数与数据总量无关。固定高度下索引靠一次除法即可得到,这是最简单、也是 el-select-v2 采用的方案。