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

 

posted @ 2022-07-05 10:05  随风&  阅读(51)  评论(0编辑  收藏  举报