<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.virtual-list__visible__area {
width: 300px;
height: 700px;
overflow: auto;
margin: 0 auto;
border: solid 1px #e5e5e5;
}
.virtual-list__list {
position: relative;
}
.virtual-list__list__item {
/*height: 70px;*/
text-align: center;
line-height: 70px;
position: absolute;
left: 0;
right: 0;
}
</style>
<body>
<div class="virtual-list__visible__area">
<div class="virtual-list__list"></div>
</div>
</body>
<script>
const list = []
for (let i = 1; i <= 10000; i++) {
list.push(`第${i}行数据`)
}
const LIST_ITEM_HEIGHT = 70
// 设置列表高度
const listArea = document.getElementsByClassName('virtual-list__list')[0]
listArea.style.height = LIST_ITEM_HEIGHT * list.length + 'px'
const BUFFER_SIZE = 20 // 可视区上面以及下面的缓冲区域渲染条数,防止划动过快出现留白
const VISIBLE_SIZE = Math.ceil(700 / LIST_ITEM_HEIGHT) // 可视区域渲染条数
let startIndex = 0 // 渲染开始项索引
let endIndex = Math.min(VISIBLE_SIZE + BUFFER_SIZE, list.length) // 渲染结束项索引
// 渲染列表
function renderVisibleAndBufferArea(startIndex, endIndex) {
listArea.innerHTML = ''
for (let i = startIndex; i < endIndex; i++) {
listArea.innerHTML += `<div class="virtual-list__list__item" style="top: ${i * LIST_ITEM_HEIGHT}px; height: ${LIST_ITEM_HEIGHT}px">${list[i]}</div>`
}
}
renderVisibleAndBufferArea(startIndex, endIndex)
// 监听可视区域滚动事件,改变渲染起始项,重新渲染列表
const visibleArea = document.getElementsByClassName('virtual-list__visible__area')[0]
visibleArea.onscroll = function (e) {
startIndex = Math.max(Math.floor(e.target.scrollTop / LIST_ITEM_HEIGHT) - BUFFER_SIZE, 0)
endIndex = Math.min(Math.floor(e.target.scrollTop / LIST_ITEM_HEIGHT) + VISIBLE_SIZE + BUFFER_SIZE, list.length)
renderVisibleAndBufferArea(startIndex, endIndex)
}
</script>
</html>