微信小程序如何优化长列表

index.js 页面

const throttle = (fn, delay) => {

  var startTime = new Date();

  return function(){

      var context = this;

      var args = arguments;

      var endTime = new Date();

      var resTime = endTime - startTime;

      //判断大于等于我们给的时间采取执行函数;

      if(resTime >= delay){

          fn.apply(context, args);

          //执行完函数之后重置初始时间,等于最后一次触发的时间

          startTime = endTime;

      }

  }

}

 

Page({

  /** 

   * 页面的初始数据

   */

  data: {

    list: []

  },

  onLoad: function() {

    this.wholePageIndex = 0;

    this.wholeVideoList = [];

    this.currentRenderIndex = 0;

    this.index =  0 ;

    this.pageHeightArr = [];

 

    wx.getSystemInfo({

      success: (res) => {

        let { windowHeight } = res;

        this.windowHeight = windowHeight;

      }

    })


 

    const arr = [  

      {

        idx: this.index++

      },

      {

        idx: this.index++

      },

      {

        idx: this.index++

      }, 

      {

        idx: this.index++

      },

 

      {

        idx: this.index++

      }

      

    ]

    this.wholeVideoList[this.wholePageIndex] = arr;

    this.setData({ ['list[' + this.wholePageIndex + ']']: arr }, () => {

      this.setHeight();

    })

  },

 

  setHeight: function() {

    const that = this;

    const wholePageIndex = this.wholePageIndex;

    this.query = wx.createSelectorQuery();

    this.query.select(`#wrp_${wholePageIndex}`).boundingClientRect()

    this.query.exec(function(res){

      that.pageHeightArr[wholePageIndex] = res[0] && res[0].height;

    });

    this.observePage(wholePageIndex);

  },

 

  // onPageScroll: throttle(function(e) {

  //   const realScrollTop = e.scrollTop;

  //   const that = this;

  //   // 滚动的时候需要实时去计算当然应该在哪一屏幕

  //   let tempScrollTop = 0;

  //   const wholePageIndex = this.wholePageIndex;

 

  //   for(var i=0;i<this.pageHeightArr.length;i++) {

  //     tempScrollTop = tempScrollTop + this.pageHeightArr[i];

  //     if(tempScrollTop > realScrollTop + this.windowHeight) {

  //       console.log('set this.computedCurrentIndex' + i);

  //       this.computedCurrentIndex = i;

  //       break;

  //     } 

  //   }

  //   const currentRenderIndex = this.currentRenderIndex;

  //   if(this.computedCurrentIndex !== currentRenderIndex ) {

  //     // 这里给不渲染的元素占位

  //     let tempList = new Array(wholePageIndex+1).fill(0);

  //     tempList.forEach((item, index) => {

  //       if(this.computedCurrentIndex-1 <= index && index <=this.computedCurrentIndex+1) {

  //         tempList[index] = that.wholeVideoList[index];

  //       } else {

  //         tempList[index] = { height: that.pageHeightArr[index]};

  //       }

  //     })

 

  //     this.currentRenderIndex = this.computedCurrentIndex;

  //     // 渲染第一屏的时候,如果之前这里有看到这里,并且showVideoIcon,那么需要重新绑定一次。

  

  //     this.setData({ list: tempList })

  //   }

  // }, 500),

 

  observePage: function(pageIndex) {

    const that = this;

    const { hasShowAlreadySaw, showMoreVideosIcon } = this.data;

    const observerObj = wx.createIntersectionObserver(this).relativeToViewport({ top: 2 * this.windowHeight, bottom: 2 * this.windowHeight });

    observerObj.observe(`#wrp_${pageIndex}`, (res) => {

      if(res.intersectionRatio <= 0) {

        that.setData({

          ['list[' + pageIndex + ']']: { height: that.pageHeightArr[pageIndex] } ,

        })

        

      } else {

        that.setData({

          ['list[' + pageIndex + ']']: that.wholeVideoList[pageIndex] ,

        })

      }

    });

  },

 

  getVideoInfoData: function () {

    const arr = [  

      {

        idx: this.index++

      },

      {

        idx: this.index++

      },

      {

        idx: this.index++

      }, 

      {

        idx: this.index++

      },

 

      {

        idx: this.index++

      }

      

    ]

    this.wholePageIndex = this.wholePageIndex + 1;

 

    const wholePageIndex = this.wholePageIndex;

    this.currentRenderIndex = wholePageIndex;

    this.wholeVideoList[wholePageIndex] = arr;

    let datas = {};

    // let tempList = new Array(wholePageIndex + 1).fill(0);

    // if(wholePageIndex > 2) {

    //   tempList.forEach((item, index) => {

    //     if(index < tempList.length -2) {

    //       tempList[index] = { height: this.pageHeightArr[index]};

    //     } else {

    //       tempList[index] = this.wholeVideoList[index];

    //     }

 

    //   })

    //   datas.list = tempList;

    // } else {

    //    datas['list[' + wholePageIndex + ']'] = arr;

    // }

    datas['list[' + wholePageIndex + ']'] = arr

 

    this.setData(datas, () => {

      this.setHeight();

    })

  },


 

  /**

 * 页面下拉触底事件的处理函数

 */

  onReachBottom: function () {

    this.getVideoInfoData();

  },

 

})

 

wxml页面

<view class="page">

  <view wx:for="{{ list }}" id="wrp_{{pageIndex}}" wx:for-index="pageIndex" wx:for-item="listSingleItem" wx:key="index">

    <view wx:if="{{ listSingleItem.length > 0 }}">   

      <view class="wrp" wx:for="{{ listSingleItem }}"  wx:for-index="index" wx:for-item="listItem" wx:key="index"> 

        当前是第{{ listItem.idx }}个元素,为第 {{ pageIndex }} 屏数据

      </view>

    </view>

    <view wx:else style="height: {{ listSingleItem.height}}px">

    </view>

  </view>

</view>

 

wxss 

.wrp {

  width: 375px;

  height: 150px;

}

 

 

这样处理的好处

1.减少了单次处理setData的数据量  官方推荐的是json.stringify不超过  256kb

2.只渲染可视范围内的真实数据  其他用包含高度的空div替代,减少了wxml的节点数  官方推荐不超过30个节点

3.使用官方推荐的ObserveAPI提升了性能  不需要借助onPageScroll