微信小程序 ---- 虚拟列表

2022-09-26  本文已影响0人  牛会骑自行车
上篇也对列表的渲染做了一定的优化,不会一次性set太多的data,不过还没有达到渲染不卡顿的目的。还有分享过一个关于小程序性能的文档,这篇的主要目的是解决第六个问题

所以从根上减少性能耗费就需要减少页面需要渲染的节点数。

思路:
1.获取最外层容器的高度
2.设置item高度
3.计算每屏可以放置几个item
4.拼接上下需要补足的区域
5.原本只需要取出屏幕展示区域的数据就好,但是上下滑动速度快时会出现来不及渲染的情况。为避免这种情况,需要在显示区域的上下都再加一部分数据。相当于展示每屏需要获取上中下三屏的数据。
6.插播一则小知识。。。。关于wxs我好奇了很久,这次有空终于好好看了看,emmmm我的理解总结起来就是:不要太依赖这个东西(虽说也没什么好依赖的😂),暂时把它当过滤器就好,用法依照VUE里的computed就成~据说IOS可以快多少多少倍来着

大概的图是这个样子(哈哈哈哈我发誓我写得很认真的怎么出来是这种潦草的效果哈哈哈哈哈哈哈虽然难看但是是工整的昂理解意思就成)

上代码😊

wxml就按照图中所示给出容器就好 ⬇️

<wxs module="computed">
  var paddingTop = function(startIndex, itemHeight) {
    return startIndex * itemHeight * 2;
  }
  var paddingBottom = function(initData, endIndex, itemHeight) {
    return (initData.length - endIndex) * itemHeight * 2;
  }
  module.exports = {
    paddingTop: paddingTop,
    paddingBottom: paddingBottom
  }
</wxs>

<!-- 容器高度需要撑起来,height为100% -->
<!-- 这个容器是为了将来抽组件方便,如果长列表用在一整个页面且不是组件的话,则不需要这个容器 -->
<view class="container h_100" id="container">
  <!-- scroll-view需要高度,还需要scroll方法来捕捉滑动的动作 -->
  <scroll-view class="scroll-container h_100" scroll-y scroll-with-animation enhanced bindscroll="handleScroll">
    <view class="outer-container" style="padding-top: {{computed.paddingTop(startIndex, itemHeight)}}rpx;padding-bottom: {{computed.paddingBottom(initData, endIndex, itemHeight)}}rpx;">
      <block wx:for="{{currentData}}" wx:key="index">
        <!-- 每行的容器需要设置高度,方便计算每屏展示的数据条数 -->
        <view class="list-item" style="height: {{itemHeight * 2}}rpx;line-height: {{itemHeight * 2}}rpx;">{{item}}</view>
      </block>
    </view>
  </scroll-view>
</view>

js ⬇️

Page({
  data: {
    //  原始数据
    initData: [],
    //  当前数据
    currentData: [],

    //  容器高度
    containerHeight: 0,
    //  每行的高度
    itemHeight: 40,
    //  每屏展示数据的条数
    showCount: 0
  },
  // 获取容器高度 ---- 设置showCount
  counting() {
    //   获取容器高度需要一点点时间,我们需要在获取到容器的高度之后再获取数据所以用了promise
    return new Promise(resolve => {
      let query = wx.createSelectorQuery();
      query.select('#container').boundingClientRect(rect => {
        let containerHeight = rect.height;
        let showCount = Math.ceil(containerHeight / this.data.itemHeight);
        this.setData({
          showCount
        })
        resolve();
      }).exec();
    })
  },
  //获取数据 
  getList() { 
    let initData = [];

    for (let i = 1; i <= 20000; i++) {
      initData.push(i);
    }
    this.setData({
      initData,
    })
    this.renderPage(0);
  },
  renderPage(scrollTop) {
    //  根据scrollTop判断该展示哪一部分数据
    let startIndex = Math.floor(scrollTop / this.data.itemHeight);
    //  showCount * 2 ---- 上滑速度太快造成的页面白屏
    let endIndex = startIndex + this.data.showCount * 2;
    if (endIndex > this.data.initData.length) {
      endIndex = this.data.initData.length;
    }
    //  将startIndex往前推也是为了解决下拉列表速度过快导致的白屏问题
    startIndex = startIndex <= this.data.showCount ? 0 : startIndex - this.data.showCount;
    //  当前展示的数据
    let currentData = this.data.initData.slice(startIndex, endIndex);

    this.setData({
      startIndex,
      endIndex,
      currentData
    })
  },
  handleScroll(event) {
    let scrollTop = event.detail.scrollTop;
    this.renderPage(scrollTop);
  },
  onLoad(options) {
    this.counting().then(() => {
      this.getList()
    });
  },
})

tada~~~一个虚拟列表就完成啦

上一篇下一篇

猜你喜欢

热点阅读