示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Virtual List</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="virtual-list-container" class="virtual-list-container">
<div id="virtual-list" class="virtual-list"></div>
</div>
<script src="script.js"></script>
</body>
</html>
body {
font-family: Arial, sans-serif;
}
.virtual-list-container {
height: 400px; /* 固定高度 */
overflow-y: auto; /* 允许滚动 */
border: 1px solid #ccc;
position: relative;
}
.virtual-list {
position: absolute;
width: 100%;
}
.virtual-list-item {
height: 30px; /* 固定高度 */
line-height: 30px;
border-bottom: 1px solid #eee;
padding: 0 10px;
box-sizing: border-box;
}
document.addEventListener('DOMContentLoaded', () => {
const itemHeight = 30; // 每个列表项的高度
const totalItems = 10000; // 总列表项数
const visibleItemCount = Math.ceil(400 / itemHeight); // 可见区域列表项数(视容器高度而定)
const buffer = 5; // 缓冲区大小
const listContainer = document.getElementById('virtual-list-container');
const virtualList = document.getElementById('virtual-list');
let startIndex = 0;
let endIndex = Math.min(startIndex + visibleItemCount + buffer * 2, totalItems);
const renderList = () => {
virtualList.innerHTML = '';
for (let i = startIndex; i < endIndex; i++) {
const listItem = document.createElement('div');
listItem.classList.add('virtual-list-item');
listItem.textContent = `Item ${i + 1}`;
listItem.style.transform = `translateY(${i * itemHeight}px)`;
// 使用 transform 而不是 top,以避免潜在的布局问题
virtualList.appendChild(listItem);
}
// 可选:为了优化性能,可以只更新可见范围内的 DOM 节点
// 例如,可以保留之前渲染的节点,并只更新它们的内容或位置
// 而不是每次都重新创建所有节点
};
const updateList = () => {
const scrollTop = listContainer.scrollTop;
startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);
endIndex = Math.min(startIndex + visibleItemCount + buffer * 2, totalItems);
renderList();
};
listContainer.addEventListener('scroll', updateList);
// 初始渲染
renderList();
});