在微信小程序 swiper 组件中,数据量过大引起卡顿性能优化方案
...大约 3 分钟
在微信小程序 swiper 组件中,数据量过大引起卡顿性能优化方案
背景
最近在做一个答题小程序,部分题型中试题数量比较大,一把带出来所有的试题,经过测试界面在试题数量大概在 100 道以上就会开始卡顿,而且试题越多,首次进来加载的时间越长。
一开始想的方案是分页进行加载,但是加载第二页的时候因为要请求接口,所以体验不是特别好。这种分页方式,还有个很大的问题,就是实现“答题卡”功能,在各个试题中跳转比较麻烦。于是在网上搜索,发现一种方案能完美解决这个问题。
简单说,就是 swiper 组件只需要准备三个 item,这三个 item 就相当于三个桶。然后设置 swiper 的 circular 属性为 true,这样可以实现循环滑动。而在滑动的过程中,我们可以通过监听 swiper 的 change 事件,来动态的更新桶中的内容。这样,不管试题有多少,我们只需要准备三个桶,就可以实现流畅的滑动效果。下面看代码:
<swiper
class="swipercard"
previous-margin="0"
next-margin="0"
:circular="true"
:autoplay="false"
:current="swiperCurrentIndex"
@change="eventHandle"
:easing-function="easeOutCubic"
:duration="300">
<block v-for="(item, index) in swiperList" :key="item.id">
<swiper-item class="swiperItem">
<view>{{item.name}}<view>
</swiper-item>
</block>
</swiper>
<script>
export default {
data() {
return {
questionList: [
{ id: 1, name: '试题1' },
{ id: 2, name: '试题2' },
{ id: 3, name: '试题3' },
{ id: 4, name: '试题4' },
{ id: 5, name: '试题5' },
{ id: 6, name: '试题6' },
{ id: 7, name: '试题7' },
{ id: 8, name: '试题8' },
{ id: 9, name: '试题9' },
], //当前题型所有的试题
swiperList: [], //swiper中显示的试题,可以看做临时试题
questionListIndex: 0, //当前展示的试题在试题list中的索引
swiperCurrentIndex: 0, //当前swiper所在的位置
};
},
onLoad() {
this.upDateSwiperList();
},
methods: {
//swiper改变时
eventHandle(e) {
// 先判断是向前滑动还是向后滑动
// current 为滑动后swiper-item的索引
let current = e.detail.current;
// swiperCurrentIndex是滑动前swiper-item的索引
// 如果两者的差为2或者-1则是向后滑动
if (
this.swiperCurrentIndex - current == 2 ||
this.swiperCurrentIndex - current == -1
) {
// 在试题列表中,如果往后滑+1,发现没有试题了,则下一题下标是第一题下标,下标是0
this.questionListIndex =
this.questionListIndex + 1 == this.questionList.length
? 0
: this.questionListIndex + 1;
//同样,在swiper这个桶中,因为只有3个桶,往后滑发现没有桶了,则下一个桶就是第一个桶,即下标是0
this.swiperCurrentIndex =
this.swiperCurrentIndex + 1 == 3 ? 0 : this.swiperCurrentIndex + 1;
// 调整完桶跟试题的下标,更新桶中的试题
this.upDateSwiperList();
}
// 如果两者的差为-2或者1则是向前滑动
else if (
this.swiperCurrentIndex - current == -2 ||
this.swiperCurrentIndex - current == 1
) {
//在试题列表中,如果往前滑-1,发现没有试题了,则下一题是最后一道题下标,下标是试题列表长度-1
this.questionListIndex =
this.questionListIndex - 1 == -1
? this.questionList.length - 1
: this.questionListIndex - 1;
//同样,在swiper这个桶中,因为只有3个桶,往前滑发现没有桶了,则上一个桶就是最后一个桶,即下标是2
this.swiperCurrentIndex =
this.swiperCurrentIndex - 1 == -1 ? 2 : this.swiperCurrentIndex - 1;
// 调整完桶跟试题的下标,更新桶中的试题
this.upDateSwiperList();
}
},
// 更新要在swiper中展示的题目
upDateSwiperList() {
let displayList = [];
// 当前显示的题目
displayList[this.swiperCurrentIndex] =
this.questionList[this.questionListIndex];
// 如果是第一题,则上一题是最后一题
displayList[
this.swiperCurrentIndex - 1 == -1 ? 2 : this.swiperCurrentIndex - 1
] =
this.questionList[
this.questionListIndex - 1 == -1
? this.questionList.length - 1
: this.questionListIndex - 1
];
// 如果是最后一题,则下一题是第一题
displayList[
this.swiperCurrentIndex + 1 == 3 ? 0 : this.swiperCurrentIndex + 1
] =
this.questionList[
this.questionListIndex + 1 == this.questionList.length
? 0
: this.questionListIndex + 1
];
this.swiperList = displayList;
},
},
};
</script>
简写中的属性
上述方案,亲测就是几千条数据,也不会卡顿。上边是 uniapp 代码,如果是原生小程序,也可以用相同的思路,按照原生小程序的思路稍微改造下即可。