js 虚拟列表

一个简单的JS虚拟列表
效果如下:
在这里插入图片描述

html部分:

<!DOCTYPE html>
<html>
  <head>
    <title>javascript 虚拟列表</title>
  </head>
  <style>
    html,body {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      font-size: 14px;
      line-height: 1.6;
      font-family: '微软雅黑';
    }
    ul, li { 
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .itemList {
        width: 100%;
        max-width: 750px;
        height: 100%;
        overflow-y: auto;
        padding: 10px 10px 0 10px;
        box-sizing: border-box;
        margin: 0 auto;
    }
    .itemList .itemArea{
        overflow: hidden;
    }
    .itemList ul { 
        width: 100%;
    }
    .itemList ul li {
        width: 100%;
        height: 100px;
        background-color: #f8f8f8;
        margin-bottom: 10px;
    }
    .itemList ul li .ibox{
        width: 150px;
        height: 100%;
        background-color: #eee;
        float: left;
        margin-right: 10px;
        display: flex;
        display: -webkit-flex;
        align-items: center;
        justify-content: center;

    }
    .itemList ul li .content {
        padding: 10px 10px 10px 0;
    }
    .itemList ul li .content h3{
        font-size: 18px;
        margin: 0;
    }
    .itemList ul li .content p{
        font-size: 12px;
    }
  </style>
  <body>
    <div class="itemList">
      <div class="itemArea">
        <ul>
        </ul>
      </div>
    </div>
  </body>
</html>

js部分:

<script>
      class List {
        constructor(options) {
          this.el = document.querySelector(options.el);
          this.data = options.data || [];
          this.itemHeight = options.itemHeight;
          this.startIndex = options.startIndex || 0;
        }
        // 初始化数据
        getData() {
          for(let i=0; i<200; i++) {
            this.data.push({pic: `图片${i+1}`, title: `标题${i+1}`, content: `内容${i+1}`})
          }
        }
        // 更新DOM
        updateHtml() {
          let itemAll = this.el.querySelectorAll(".item");
          for(let i=this.startIndex, j=0, len=this.pageSize+this.startIndex; i<len && i<this.data.length; i++, j++) {
            itemAll[j].querySelector(".ibox").innerHTML = this.data[i].pic;
            itemAll[j].querySelector(".content h3").innerHTML = this.data[i].title;
            itemAll[j].querySelector(".content p").innerHTML = this.data[i].content;
          }
        }
        // 滚动处理
        handleScroller() {
          return () => {
            let scrollTop = this.el.scrollTop; // 滚动高度
            let fixedScrollTop = scrollTop - scrollTop % this.itemHeight; // 内容区域Y轴偏移,确保
            let startIndex = Number.parseInt(scrollTop / this.itemHeight);

            // 当开始位置有变化,则执行
            if(this.startIndex != startIndex) {
              this.startIndex = startIndex
              this.el.querySelector(".itemArea ul").style.transform = 'translateY(' + fixedScrollTop + 'px)';
              this.updateHtml();
            }
          }
        }
        default() {
          let html = "";
          for(let i=this.startIndex, j=0, len=this.pageSize+this.startIndex; i<len && i<this.data.length; i++, j++) {
            html+=`
            <li class="item">
              <div class="ibox">${this.data[i].pic}</div>
              <section class="content">
                <h3>${this.data[i].title}</h3>
                <p>${this.data[i].content}</p>
              </section>
            </li>`;
          }
          this.el.querySelector(".itemArea ul").innerHTML = html;
          // 内容高度
          this.el.children[0].style.height = this.itemHeight * this.data.length + 'px';
        }
        // 当窗口改变
        resize() {
          window.onresize = () => {
            this.pageSize = Math.ceil(
              this.el.offsetHeight / this.itemHeight 
            );
            if(this.startIndex + this.pageSize >= this.data.length) {
                this.startIndex = 0;
                this.el.querySelector(".itemArea ul").style.transform = 'translateY(0px)';
            }
            this.default()
          }
        }
        // 初始化
        init() {
          // 初始化数据
          if(this.data.length<1) this.getData(); 

          // 获取一个滚动屏 最大可容纳 几个 子元素
          this.pageSize = Math.ceil(
            this.el.offsetHeight / this.itemHeight 
          ) + 1;

          // 初始化节点
          this.default()

          // Scroll监听
          this.el.addEventListener('scroll', this.handleScroller.call(this), false);

          // Window resize
          this.resize();
        }
      }
      
      /**
       * class List
       * 
       * el - DOM对象
       * data - 初始化数据
       * itemHeight - 列表子集元素高度
       * startIndex - 起始数据下标
       * 
      */
      let list = new List({
        el: ".itemList",
        data: [],
        itemHeight: 110,
        startIndex: 0
      })

      list.init();
    </script>
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值