微信小程序虚拟列表
为啥使用长列表
需要展示长列表,无限下拉都会一直显示出更多的数据。但是当一个页面展示的DOM节点过多的时候,会造成小程序页面的卡顿,点击反应迟钝,严重的会直接白屏。
原因有几点
- 列表数据很大,不断获取下一屏的数据,setData的数据越来越多的时候耗时高
- 渲染DOM 结构多,每次 setData 都需要创建新的虚拟- 树、和旧树 diff 操作耗时都比较高
- DOM 结构多,占用的内存高,造成页面被系统回收的概率变大,会白屏
首先想到的是使用二维数组
- 首先开始是每次渲染数据都重新进行push,然后setData赋值,但是这样做的效果是数据过多时就会出现卡顿,白屏
- 于是着手把数据变成二位数组,setData时只对当前索引赋值这样的好处是可以减轻setData数据
本以为这样的话可以解决但是试了试数据过大时仍然卡顿,dom渲染还是很多,于是只渲染在当前屏幕的,其他位置用空标签占位
解决方案:
方案1
<block >
<block
wx:for="{{infoList}}"
wx:for-item="infoItemList"
wx:for-index="pageNum"
wx:key="pageNum">
<info-item
custom-class="info-item"
useCustomSlot="{{false}}"
wx:for="{{infoItemList}}"
data-index="{{index}}"
data-page="{{pageNum}}"
wx:key="id"
info="{{item}}"
>
</info-item>
</block>
</block>
- 有两层循环,第一层循环最外层的(二维数组索引),第二层循环每屏数据info-item是封装的每个item展示数据
- 现在做的就是在这上面优化让在视图内的显示数据,不在试图内的让view标签占位
- 接着我们存储每屏高度,然后记录滚动距离,获取现在应该渲染那几屏 滚动距离
根据这个滚动距离以及每一屏的高度,来计算当前应该渲染哪一屏的数据。这个需要怎么去算?其实很简单,循环去遍历每屏高度,用第一屏的高度 与滚动高度 + 当前屏幕的高度this.windowHeight做比较,如果滚动高度比较小,则用第一屏累加第二屏的高度,一直到第一屏幕累计高度 > 滚动高度 + this.windowHeight 就是当前应该渲染的屏幕。
方案2:
wx.createIntersectionObserver