HTML结构:
包含一个滚动容器#scrollContainer,其中有两个子元素#placeholder和#content。
#placeholder将用作占位符,以设置滚动条的高度,
#content将包含实际渲染的列表项。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虚拟滚动示例</title>
<style>
#scrollContainer {
height: 300px;
overflow-y: auto;
border: 1px solid #ccc;
}
.item {
height: 50px;
box-sizing: border-box;
padding: 10px;
border-bottom: 1px solid #eee;
}
#placeholder {
width: 0;
float: left;
}
</style>
</head>
<body>
<div id="scrollContainer">
<div id="placeholder"></div>
<div id="content"></div>
</div>
<script src="./index.js"></script>
</body>
</html>
JavaScript实现:
设置占位符#placeholder的高度,以反映所有数据的高度。
在renderItems函数中,根据起始和结束索引渲染元素到#content中。
在onScroll函数中,计算当前可视区域的起始和结束索引,并重新渲染这些元素。
document.addEventListener("DOMContentLoaded", () => {
const scrollContainer = document.getElementById("scrollContainer");
const totalItems = 1000;
const itemHeight = 50;
const containerHeight = 300;
const buffer = 5; // 缓冲区,预加载额外元素
// 计算可见元素的数量
let visibleItems = Math.ceil(containerHeight / itemHeight) + buffer * 2;
let renderStart = 0;
let renderEnd = visibleItems;
const data = Array.from({ length: totalItems }, (_, i) => `Item ${i + 1}`);
// 设置滚动容器的高度,以反映所有数据
scrollContainer.style.height = `${containerHeight}px`;
scrollContainer.style.overflowY = "auto";
scrollContainer.style.position = "relative";
// 创建占位元素,用于计算滚动位置
const placeholder = document.getElementById("placeholder");
placeholder.style.height = `${totalItems * itemHeight}px`;
// 渲染初始可见元素
const content = document.getElementById("content");
function renderItems(start, end) {
content.innerHTML = "";
for (let i = start; i < end; i++) {
const item = document.createElement("div");
item.className = "item";
item.textContent = data[i];
content.appendChild(item);
}
}
function onScroll() {
const scrollTop = scrollContainer.scrollTop;
renderStart = Math.floor(scrollTop / itemHeight) - buffer;
renderEnd = renderStart + visibleItems;
renderStart = Math.max(renderStart, 0);
renderEnd = Math.min(totalItems, renderEnd); // 确保不超过总元素数
console.log(
`Render start: ${renderStart}, Render end: ${renderEnd}, Scroll top: ${scrollTop}`
); // 调试信息
// 设置内容容器的 margin-top,实现滚动效果
content.style.marginTop = `${renderStart * itemHeight}px`;
renderItems(renderStart, renderEnd);
}
scrollContainer.addEventListener("scroll", onScroll);
// 初始渲染
renderItems(renderStart, renderEnd);
});