Bootstrap

小程序长列表优化,解决数据过多白屏问题

小程序长列表优化,解决数据过多白屏问题

场景: 使用mpvue框架,列表数据量过大
解决方法-分页渲染数据,列表滚动时将可视区域外元素数据清空只保留高度
先贴代码,有注释

html

<template>
  <!--index.wxml-->
  <div class="list-box">
    <div
      :id="'page'+pindex"
      class="list-page"
      :style="{height:pitem.height ? pitem.height+'px':'auto'}"
      v-for="(pitem,pindex) in list"
      :key="pindex"
    >
      <section v-if="pitem.length > 0">
        <div class="list-item" v-for="(item,index) in pitem" :key="index">{{item}}</div>
      </section>
    </div>
  </div>
</template>

js

<script>
export default {
  data() {
    return {
      list: [],
      page: 1,
      pageNumber: 10,
      allData: []
    };
  },
  methods: {
    loadData() {
      // 先为dom渲染数据,才能在下面的dom数据获取中拿到dom数据
      let data = [];
      let oldDt = JSON.parse(JSON.stringify(this.list));
      for (let i = 0; i < this.pageNumber; i++) {
        data.push(1 + i + (this.page - 1) * this.pageNumber);
      }
      if (this.page == 1) {
        this.list = [];
      }
      this.allData.push(data);
      oldDt[this.page - 1] = data; //缓存数据,优化性能时使用
      this.list = oldDt;

      //计算并记录数据的边界值
      this.boundings = Array.isArray(this.boundings) ? this.boundings : [];
      let index = this.page - 1;
      // 通过延迟的方式去获取dom数据
      setTimeout(() => {
        const query = wx.createSelectorQuery();
        query
          .select(`#page${index}`)
          .boundingClientRect(rect => {
            this.boundings[index] = {
              height: rect.height, //高度
              top:
                index == 0
                  ? rect.top
                  : this.boundings[index - 1].top +
                    this.boundings[index - 1].height, //上边界
              bottom:
                index == 0
                  ? rect.bottom
                  : this.boundings[index - 1].bottom + rect.height //下边界
            };
          })
          .exec();
        wx.stopPullDownRefresh();
        wx.hideLoading();
      }, 1000);
    }
  },
  onReady() {
    this.loadData();
  },
  onUnload() {},
  onPageScroll(e) {
    //当前与滚动区域底部相交的元素索引
    this.index = this.index ? this.index : 0;
    this.windowHeight = this.windowHeight
      ? this.windowHeight
      : wx.getSystemInfoSync().windowHeight;
    this.boundings.forEach((item, index) => {
      // 如果没有在屏幕中,并且视野的高度小于我的结尾位置距离顶部的距离,也就是说,这个dom是我正在查看的dom
      if (
        item.top < e.scrollTop + this.windowHeight &&
        e.scrollTop + this.windowHeight <= item.bottom
      ) {
        this.index = index;
      }
    });

    //当前相交元素的前2后2元素显示,超出部分隐藏
    let oldarr = JSON.parse(JSON.stringify(this.list));
    oldarr.forEach((item, index) => {
      // 这里的意思是渲染了三页的数据,并且list这一页有数据,并且数据是obj
      if (
        (index == this.index ||
          index == this.index - 1 ||
          index == this.index - 2 ||
          index == this.index + 1 ||
          index == this.index + 2) &&
        oldarr[index] &&
        !Array.isArray(oldarr[index])
      ) {
        // 是的话就替换成我们的数组数据
        oldarr[index] = this.allData[index];
      }
      // 这里是指当前索引页不是显示区域数据判断,并且数据类型是数组
      if (
        (index > this.index + 2 || index < this.index - 2) &&
        Array.isArray(oldarr[index])
      ) {
        // 是的话就替换成我们的dom高度数据
        oldarr[index] = { height: this.boundings[index].height };
      }
    });
    this.list = oldarr;
  },
  onPullDownRefresh() {
    this.page = 1;
    setTimeout(() => {
      this.loadData();
    }, 1000);
  },
  onReachBottom() {
    this.page = ++this.page;
    wx.showLoading();
    setTimeout(() => {
      this.loadData();
    }, 1000);
  }
};
</script>

less

<style lang="less" scoped>
.list-item {
  height: 200rpx;
  background: #ddd;
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: 1px solid #fff;
}
</style>

有详细备注就不多说了。自己看代码啦。代码参考这位大佬的小程序原生代码,点击可跳转,大佬有小程序代码片段

;