gdutjason / front-end-knowledge

0 stars 0 forks source link

虚拟列表的简单实现 #2

Open gdutjason opened 1 year ago

gdutjason commented 1 year ago
<html>
  <style>
    /* 设置偶数项的背景颜色 */
    #content div:nth-child(even) {
      background-color: #eee;
    }

    /* 设置奇数项的背景颜色 */
    #content div:nth-child(odd) {
      background-color: #fff;
    }
  </style>
  <body>
    <div id="viewport" style="height: 400px; overflow-y: scroll">
      <div id="content"></div>
    </div>
  </body>
  <script type="text/javascript">
  const viewport = document.getElementById('viewport');
  const content = document.getElementById('content');
  const itemCount = 100; // 列表项的总数
  const itemHeight = 50; // 列表项的高度
  const viewportHeight = viewport.offsetHeight; // 视口的高度
  const visibleCount = Math.ceil(viewportHeight / itemHeight); // 可见项的数量
  const totalHeight = itemCount * itemHeight; // 列表的总高度
  // const totalHeight = visibleCount *2 ;

  // 设置容器的高度
  content.style.height = `${totalHeight}px`;

  const update = () => {
    const scrollTop = viewport.scrollTop;
    const startIndex = Math.floor(scrollTop / itemHeight);
    const endIndex = Math.min(startIndex + visibleCount, itemCount);
    const items = [];
    // content.style.paddingTop = `${scrollTop}px`;
    let tansY = startIndex * itemHeight;
    // 渲染可见项
    for (let i = startIndex; i < endIndex+100; i++) {
      const item = document.createElement('div');
      item.innerText = `Item ${i}`;
      item.style.height = `${itemHeight}px`;
      item.style.transform = `translateY(${tansY}px)`; // 设置垂直偏移量
      items.push(item);
    }

    // 使用 requestAnimationFrame() 延迟渲染新的可见项
    window.requestAnimationFrame(() => {
      content.innerHTML = '';
      content.append(...items);
    });
  }
  update()
  // 监听滚动事件
  viewport.addEventListener('scroll', update);
  </script>
</html>
gdutjason commented 1 year ago

基于基础的虚拟列表,可以引深问题有 1、实现上下缓冲区 2、item高度不一致时的实现 3、自定义滚动条实现