前言
swiper的加载太多问题,网上资料好像没有一个特别明确的,就拿这个答题页,来讲讲我的解决方案
这里实现了如下功能和细节:
- 保证swiper-item的数量固定,加载大量数据时,大大优化渲染效率
- 记录上次的位置,页面初次加载不一定非得是第一页,可以是任何页
- 答题卡选择某一index回来以后的数据替换,并去掉swiper切换动画,提升交互体验
示例动图
截图
问题原因
当swiper-item数量很多的时候,会出现性能问题
我实现了一个答题小程序,在一次性加载100个swipe-item的时候,低端手机页面渲染时间达到了2000多ms
也就是说在进入答题页的时候,会卡顿2秒多去加载这个100个swiper-item
思考问题
那我们能不能让他先加载一部分,然后滑动以后再去改变item的数据,让swiper一直保持一定量的swiper-item?
注意到官方文档有这么两个属性可以利用,我们可以开启衔接滑动,然后再bindchange方法中去修改data
1、保证swiper-item的数量固定,加载大量数据时,大大优化渲染效率
假设我们请求到的数据的为list,实际渲染的数据为swiperList
我们现在给他就固定3个swiper-item,前后滑动的时候去替换数据
正向滑动的时候去替换滑动后的下一页数据,反向滑动的时候去替换滑动后的上一页数据
当我们知道了要替换的条件,我们便可以去替换数据了
但是我们应该考虑到临界值的问题,如果当前页是list第一项和最后一项该怎么办,向左向右滑是不是得禁止啊
2、记录上次的位置,页面初次加载不一定非得是第一页,可以是任何页
有很多时候,我们是从某一项直接进来的,比如说上次答题答到了第五题,我这次进来要直接做第六题
那么我们需要去初始化这个swiperList,让它当前页、上一页、下一页都有数据
3、答题卡选择某一index回来以后的数据替换,并去掉swiper切换动画,提升交互体验
从答题卡选择index,那就不仅仅是滑动上下页了,它可以跳转到任何页,所以也采用类似初始化swiperList的方法
swiper切换动画我这边是默认250ms,但是发现有时候从答题卡点击回来,你在答题卡点击的下一项不知道会从左还是从右滑过来
体验真的很差,一开始不知道怎么禁掉动画,其实在跳转到答题卡页的时候把duration设为0就可以了
我然后在答题卡页的unload方法中恢复
关键点:
在固定3个swiper-item的同时,保证我们可以有办法来替代微信自带swiper的current属性和change方法
swiper-limited-load使用方法及说明:
- 将components中的swiper-limited-load复制到您的项目中
- 在需要的页面引用此组件,并且创建自己的自定义组件item-view
- 在初始化数据时,为你的list的每一项指定index属性
- 具体可以参照项目目录start-swiper-limited-load中的用法
- 说明:其它属性和swiper无异,你们可以自己单独添加你们需要的属性
总结
一开始很头疼,为什么微信小程序提供的这个swiper,那么的不好用,和ViewPager差太远了吧。
然后在网上和社区找也没有一个特别好的解决方案。
后来想想,小程序是小程序,原生是原生。遇到需求就静下来解决吧。
项目地址:swiper-limited-load
如果错误,欢迎指出。
如有新的需求也可以提出来,如果有时间的话,我会帮你们完善。
如果能帮到你们,记得给一个star,谢谢。
———补充
有很多朋友在评论区提到了分页的需求,抽时间写了一个分页的Demo和大家分享一下。
还是以答题为例,比如我们一共有500条数据,一页20条,可能需要如下功能,乍一看不就加了个分页,挺简单的,其实实现起来挺麻烦的,下面说一下思路和一些需要特别注意的点:
1、从其他页面跳转到答题页时,不光只能默认在第一题,可以是任意一题,比如第80题。
跳转到任意一题,那么需要我们根据index算出该数据在第几页,然后需要请求该页数据,最后显示对应的index。我的思路更注重用户体验,不可能是上滑或者下滑才开始去请求数据,一定是要用户滑动前提前请求好数据。所以起码要保证左右两侧在初始化那一刻都有数据。如果此题和它的上一题下一题都在同一页,那么我们只需要请求一页数据(第15题,那么只需请求第1页数据)。如果此题和它的上一题或者下一题不在同一页,那么我们可能需要请求两页数据。(第20题,那么需要请求第1页和第2页数据)
2、左滑、右滑没数据时,都可以加载新数据。直到滑到第一题或者最后一题。
如果我们初始化时是第24题,那么我们左滑到第21题时,就应该去请求第一页的数据。那么用户在看完21题时,再滑到20题,可能就根本不会感知到通过网络请求了数据。但是如果用户此刻滑动特别快:滑到21题时请求了网络,请求还没成功,就又向左滑了。那么我们需要限制用户的滑动,给用户一个提示:数据正在加载中。
3、从答题卡点击任意一题可以跳转到相应的题目,并且左右滑动显示正常数据
比如我们初始化是跳转到了第80题,不一会点击答题卡又要跳转到200题,一会又跳转到150题。各种无序操作,你也不知道用户要往哪里点。
一开始是想着维护一个主list,点到哪道题往list中添加这道题所在的当页的数据,但是还得判断这一页或者左滑右滑请求新一页的数据得往list的哪个位置添加。这来回来去乱七八糟的判断就很麻烦了,很容易出bug。而且list长度太长了以后insert的性能也不好。
后来就去想,要不答题卡点击任意一题都清空旧的list,然后请求新的数据,左右滑动没数据了再请求新的数据呗。但是这样很浪费资源,并且用户体验也不好,用户已经从第1题答到第200题了,这时用户从答题卡选择了一个25题,还得重新请求网络。而且200道题的数据都没了,那再选个26题,再重新请求网络?网络有延时不说,还浪费资源。
最后转念一想,这时候就需要弄一个缓存了。所以最终的解决方法就出来了:我们维护一个map,在网络请求成功后,在map中保存对应页的数据,同时我们维护一个主list来显示对应的题目。当我们在答题卡选择某一题目,就清空list,然后判断map中有没有该页的数据,如果有就直接拿来,没有就再去网络请求。这个处理方式,写法相对来说简单,不需要乱七八糟的判断,也不浪费资源,用户体验也很不错。
总结
以上就是一些思路和要注意的地方。这个Demo断断续续花了好几天时间写出来的。可能我说的比较啰嗦比较细,只是想让需要用到这个分页Demo的同学能理解我是如何实现的。
如果觉得能帮到你,记得给一个star,谢谢。同时如果这个demo有bug或者你们有新想法,欢迎提出来。