自学内容网 自学内容网

前端超长列表,虚拟滚动实现

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>虚拟滚动</title>

    <style>
      .container {
        width: 300px;
        height: 500px;
        overflow: hidden;
        border: 1px solid #ccc;
        margin-top: 50px;
      }
      .scroll-box {
        width: 100%;
        height: 100%;
        overflow-y: auto;
        overflow-x: hidden;
        position: relative;
      }
      .scroll-height-main{
        width: 100%;
        position: absolute;
        top: 0;
        left: 0;
      }
      .list-box{
        overflow: hidden;
      }
      .item {
        width: 100%;
        height: 50px;
        display: flex;
        align-items: center;
        padding: 10px;
        border-bottom: 1px solid #eee;
        box-sizing: border-box;
        position:absolute;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="scroll-box">
        <div class="scroll-height-main"></div>
      </div>
    </div>

    <script>
      const scrollBoxDom = document.querySelector('.scroll-box')
      const scrollHeightMainDom = document.querySelector('.scroll-height-main')
      const itemHeight = 50
      // 缓冲条数
      const buffer = 2

      // 最多支持40w数据
      const list = Array.from({ length: 100000 }, (_, index) => `这是第${index + 1}个元素`)
      const itemCount = list.length

      // 默认出现滚动条
      scrollHeightMainDom.style.height = (itemCount * itemHeight) + 'px'

      // 移除之前的dom
      function clearChildDom() {
        scrollBoxDom.querySelectorAll('.item').forEach(itemDom=>{
          itemDom.remove()
        })
      }

      // 插入dom
      function insertDom(start, end) {
        clearChildDom()

        const createItem = (index)=>{
          const newChild = document.createElement('div')
          newChild.className = 'item'
          newChild.style.transform = `translateY(${index * itemHeight}px)`;
          newChild.innerHTML = list[index]
          return newChild
        }
        for (let i = start; i <= end; i++) {
          scrollBoxDom.appendChild(createItem(i))
        }
      }

      // 初始化
      insertDom(0, Math.ceil(scrollBoxDom.offsetHeight / itemHeight))

      scrollBoxDom.addEventListener('scroll', () => {
        const scrollTopVal = scrollBoxDom.scrollTop

        /**
         * @target 得到起始下标
         * 滚动距离可以放多少个子元素
         * 向下取整后-缓冲数量
         * 再和最小index取最大值
        */
        const startIndex = Math.max(0,Math.floor(scrollTopVal / itemHeight) - buffer) 

        /**
         * @end 得到结束下标
         * 向上取整(可视区域可以放多少子元素) + 起始下标 + 缓冲区*2  多缓冲一些
         * 再和最大index取最小值,endIndex不能超出list最后一项
        */
        const endIndex = Math.min(itemCount-1, Math.ceil(scrollBoxDom.clientHeight / itemHeight) + startIndex + buffer*2)

        insertDom(startIndex, endIndex)
      })
    </script>
  </body>
</html>


原文地址:https://blog.csdn.net/weixin_44260173/article/details/143860624

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!