虚拟列表优化核心是只渲染20–50个真实节点,用transform: translateY定位、contain: layout paint隔离渲染、passive: true滚动监听,并确保容器高度固定、scrollTop可信、列表项高度可预测。

直接渲染上万条 这两种方式只是让元素不可见,但 DOM 节点仍在文档中,浏览器仍要为每个节点计算布局(layout)、生成绘制列表(paint)、维护层叠上下文(stacking context)。10 万条 虚拟列表的核心是只渲染约 20–50 个真实节点,靠定位“模拟”滚动位置。一旦用 Chrome 对未声明 在 最易被忽略的一点:所有“可视区域计算”都建立在容器高度可控、 或 是滑动卡顿的根源——浏览器不是被 JS 拖垮的,而是被 DOM 树本身压死的。真正有效的优化,是把可视区域外的节点彻底移出渲染流,而不是“藏起来”或“用 CSS 优化”。 为什么 display: none / visibility: hidden 不解决问题
display: none,DevTools 里 DOM 节点数照旧破万,Performance 面板 layout 时间持续红条。
visibility: hidden 还会保留占位,可能影响父容器尺寸计算display 属性,等于每帧都触发重排(reflow)必须用 transform: translateY() 定位,禁用 top/margin/padding
top、marginTop 或 paddingTop 推动内容,每次滚动都会强制浏览器重新计算整个容器内所有元素的几何位置。
position: absolute,用 transform: translateY(${offset}px) 移动contain: layout paint,显式告诉浏览器“不可见区域无需参与布局与绘制”width: fit-content、flex: 1 等需回溯父级尺寸的属性,它们会破坏 contain 效果滚动监听必须 passive: true,且不能依赖 scrollTop 实时算索引
{ passive: true } 的 scroll 监听器会强制同步执行 handler,哪怕你只读 scrollTop,也会打断 requestAnimationFrame 流程,导致掉帧。
window.addEventListener('scroll', handler, { passive: true })
scrollTop 值必须来自带固定高度的容器(如 style="height: 600px; overflow-y: auto;"),不能用 document.documentElement.scrollTop —— 后者在嵌套滚动或 flex 容器里常返回 0 或 NaN
Math.floor(scrollTop / itemHeight);只要存在任意一项高度不同(比如含图片、展开态描述),就必须预构建前缀和数组 + 二分查找,否则 findIndex 在 10 万条数据下主线程直接冻结自定义元素中禁止 innerHTML 渲染长列表
connectedCallback 里拼字符串再赋值给 innerHTML,等于每次滚动或更新都触发完整 DOM 解析 + 重建,性能随数据量线性恶化。1000 条就开始卡,1 万条基本无法交互。
+ template.content.cloneNode(true) 克隆结构,不是 template.innerHTML(后者为空字符串)this.attachShadow({ mode: 'open' }) 必须在 constructor 或 connectedCallback 中调用,否则后续插入失败scrollTop 可信、列表项高度可预测这三点之上。任一环节失控(比如父容器用了 min-height、列表项含未加载图片、滚动容器被 overflow: hidden 截断),整个虚拟逻辑就会错位甚至崩溃。先稳住这三条,再谈优化。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











