虚拟滚动通过只渲染可视区域内容、用空白div占位撑高滚动条、动态替换视口内容来节省dom;需固定容器高度、唯一key、合理缓冲区,避免不设高度、未重算、缓冲失当及复杂组件导致的性能问题。

虚拟滚动不是加个插件就完事,关键在理解它怎么“省DOM”、什么时候该用、以及容易踩哪些坑。
为什么非得用虚拟滚动?
数据一过几千条,传统 v-for 或 map 渲染就会明显变卡。浏览器要一次性创建成千上万个 DOM 节点,还要计算样式、布局、绘制——光是首次渲染就可能卡住主线程 1 秒以上。滚动时更糟:每动一点,浏览器都在重排重绘,帧率掉到 10fps 以下,手指一滑,页面就“糊”了。
核心就三点:只画眼睛看得见的,撑出滚动高度,滚动时快速换内容
- 视口(viewport)内必须渲染,这是用户当前看到的部分
- 视口上下留几行缓冲区(比如 keeps=30),防止快速滚动时闪白
- 所有不可见区域用空白
<div> 占位,高度 = 总数据量 × 单项高度,这样滚动条长度和位置才准确 <p><strong>实操中必须配对的参数</strong> </p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6092" title="Dagre React Flow"><img src="https://img.php.cn/upload/skill/000/000/081/179077341115225.jpg" alt="Dagre React Flow" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill6092" title="Dagre React Flow" class="overflowclass">Dagre React Flow</a> <p class="overflowclass">使用 dagre 与 React Flow (@xyflow/react) 实现自动图布局。适用于自动布局、层级布局、树形结构或节点排列等场景。</p> </div> <a rel="nofollow" href="/xiazai/skill6092" title="Dagre React Flow" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> <ul> <li>容器要有固定高度(如 <code>height: 500px),否则算不出可视范围 - 每条数据得有唯一 key(如
row-key="id"),方便复用节点、避免重渲染 - 如果行高不固定,选支持动态尺寸的库(如
vue-virtual-scroll-list的estimated-item-size),别硬套固定高度方案
常见翻车现场
- 忘记设容器高度 → 列表直接不显示或高度塌陷
- 数据更新后没触发重新计算(比如过滤、搜索)→ 视口错位、内容重复或缺失
- 缓冲区太小(100)→ 失去优化意义,DOM 又多起来
- 在虚拟列表里放复杂组件(含大量 watch、computed、第三方 UI)→ 单个 item 渲染变慢,整体还是卡
不同框架简单对照
- Vue:
vue-virtual-scroll-list上手最快,3 个 props 就能跑;vue-virtual-scroller更灵活但配置稍多 - React:可用
react-window或react-virtualized,API 清晰,支持 variableSizeList - Angular:RxAngular 虚拟滚动比 CDK 更快,尤其百万级数据下任务调度更轻量
- DevUI/Ant Design Vue:表格需显式开启
virtual-scroll,并传row-key和固定height
本质上,虚拟滚动不是黑魔法,而是用“空间换时间”的理性妥协:少建 DOM,多算坐标。只要把可视逻辑理清、参数配准,万级甚至百万级列表也能滑得跟丝一样顺。









