固定行高列表可以保留一个代表总高度的占位层,根据 scrolltop 算出可见区,只渲染这段记录和少量缓冲行。渲染层的偏移等于首个渲染索引乘以行高。

建立固定高度的视口和占位层
保存为 demo.html,行高固定为 32 像素。
<style>
#viewport { height: 320px; overflow: auto; }
#space { position: relative; }
#rows { position: absolute; inset: 0 0 auto; }
.row { height: 32px; line-height: 32px; overflow: hidden; }
</style><div id="viewport"><div id="space"><div id="rows"></div></div></div>

占位层负责提供滚动范围,绝对定位的行不会把总高度撑大。
从滚动位置计算索引并渲染
将脚本放在 HTML 标记后面。
<script>
const viewport = document.querySelector("#viewport");
const space = document.querySelector("#space");
const rows = document.querySelector("#rows");
const rowHeight = 32;
const count = 10000;
const overscan = 3;
space.style.height = count * rowHeight + "px";
function render() {
const top = Math.max(0, viewport.scrollTop);
const start = Math.max(0, Math.floor(top / rowHeight) - overscan);
const end = Math.min(count,
Math.ceil((top + viewport.clientHeight) / rowHeight) + overscan);
const fragment = document.createDocumentFragment();
for (let index = start; index < end; index++) {
const row = document.createElement("div");
row.className = "row";
row.textContent = "记录 " + (index + 1);
fragment.append(row);
}
rows.style.transform = "translateY(" + start * rowHeight + "px)";
rows.replaceChildren(fragment);
}
viewport.addEventListener("scroll", render, { passive: true });
render();
</script>
缓冲行越多,当前渲染的节点就越多。这个计算依赖所有行实际高度相同。
核对视口和节点数量
在控制台跳到靠后的记录并检查节点数。
document.querySelector("#viewport").scrollTop = 32000;
document.querySelectorAll("#rows .row").length;
滚动事件处理后应看到约第 1001 条,节点数通常不超过 17。动态行高需要维护各行高度和偏移。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











