一个简单的虚拟列表demo
<!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>