最近做项目的过程中遇到无限加载的问题,主要是当商品数据比较多时页面卡顿的问题,以及解决办法。
可能很多小伙伴都已经做过这样的业务,而且网上也有很多很成熟的框架,下拉更新,上滑加载更多很常见的业务场景。
以前也做过这样的业务,不过页面布局相对来说简单一些,并没有发现问题,这次的应用场景相对复杂,页面中有四处需要滑动的地方
1、3、4分别是导航区域,2是内容展示区域点击不同的导航切换不同的内容,并且区域2内还要有无限滚动还要下拉切换上一个分类,内容中商品有图片、标题、价格、销量、平台等等信息,页面比较复杂,不多赘述,这里只是形容下复杂情况无限加载遇到的问题。
先来说下主要问题,就是卡,内容加载多了后就会卡,ios表现很不错,但安卓数据多了后惨不忍睹。
页面滑动的形式基本有三种
一、body的整体滚动,
优势很明显,第一不卡,完美的解决方案,很流畅,无论是ios还是安卓,第二省心,内容多了自动就有滚动条,
劣势就是不能分层,例如拿上图示例,如果用body滚动,区域2就是body内容区域,1、3、4则是fixed定位上去的压倒的body 上,模拟出衔接在旁边的感觉,正常情况下没有问题,互不干扰,但是快速滑动一下区域二让他滚动起来,然后在滚动未停止的时候滑动区域三,会发现你滑动的不是区域三还是区域二(虽然你手指在区域三内,但没卵用)而且你也没有办法来阻止这种行为,因为在这种快速的惯性滑动时候你拿不到任何的回调,手指在区域3中的touch回调是不触发的。
二、div区块滚动
div滚动控制好高度,给上overflow-y:scroll 当内容过高时会出现滚动条达到可以区域滚动的目的。
优势:性能方面过得去,(简单的布局情况下)虽然比不上body但是也在接受范围,主要的是比较自由相互之间不影响。
劣势:微信浏览器中ios 在顶部下拉会触发默认的弹性滑动,这里的滑动分两种 一种是在顶部下拉,会显示“此网页由 XXX.XXX.XXX 提供” 俗称露底(body滚动也存在这种情况),另一种是在顶部的时候向上回一小下,再下拉也会出现这种弹动但没有 提供信息什么的 第二种情况是div的默认滚动,当然这些都可以使用代码解决,判断手指移动距离以及方向可以用阻止默认行为的方式来避免,当然这也是一些小烦恼,但是碰到复杂情况的布局商品加载超过二百条后,ios表现可以,安卓只用用惨烈形容。
三、css3模拟滚动,自己画滚动条
利用transform translate(0px, 0px) 控制div的位移方向,然后再按照比例画个滚动条出来,
优势:控制性强,各种回调函数可拿,各种位置可控制,而且解决安卓下没有触底后的弹性滚动问题,很人性化,并且有的框架自身集合了下拉刷新和上拉加载的回调,就算没有提供,根据框架的各种回调想写一个也是事半功倍。
劣势:只能应付简单的布局,场景复杂后ios表现尚可,安卓比惨烈更惨烈,数据多了后像看ppt一样还不如ppt流程。写个静态的列表或是分类集合什么的还是蛮不错的选择。
尝试了几款市面上主流的框架,jroll 2 better-scroll iscrol 他们的原理差不多,使用的方法也差不多,个人感觉 iscrol 优于 jroll 2 better-scroll, jroll 2 优于 better-scroll,但是也没卵用哪个都没有达到满意的程度。
经过几次实验都没有最终的解决问题,但是大概的摸清了几种滑动方式的优缺点,body滚动 > div区间滚动 > css3模拟滚动(不要在意命名,这是我自己取的名)
首先问题出现了 比较卡 解决问题第一步向来都是找到问题根源才能对症下药,所以首先思考时哪里造成的卡顿,有三种猜想
1 加载卡顿
页面打开首先要加载数据 数据获取到要根据商品图片的src 去获取图片,是不是这层层数据加载造成的卡顿
2 渲染的卡顿
刚开始数据在两百条以内还是满流程,随着数据越来越多 需要渲染的图片文字增多 会不会是内容太多造成的渲染卡顿
3 布局的卡顿
简单样式布局情况下很流畅,是不是页面中渲染的布局div层层嵌套过多造成的卡段
问题分析出来 总结可能造成卡顿问题的关键点 接下来就是开始一一测试
根据上面的总结 前后测试了几次 分别 模拟数据(阻断了加载)去掉图片渲染 以及改变布局
发现和数据加载没有关系,不渲染图片页面明显流程了一些,改变成简单布局了以后又上升了一些。
找到了关键点 其实就是渲染的问题,但是也不能不渲染,啥都不显示肯定嘎嘎快但是人家用户看啥,采取战略减少渲染的商品,思路根据用户所浏览的位置,展示用户当前所能看见区域的商品,其余商品隐藏,滑动技术用div区块滑动
红色是当前用户屏幕所在区域,黄色部分是渲染的商品,其余部分是未渲染商品,用户每次滑动都根据屏幕距离头部的距离进行计算, 得出用户正在浏览区域的商品然后上下预加载两个防止用户往回滑动,这样就最小程度的保证了渲染的数量。
但是测试结果还是不尽人意,因为计算量太大了每次滑动都要进行百次的计算,滑动的回调次数很密集,而且用户浏览滑动时会很频繁的释放和加载不同的商品,这些也都很耗费性能。
所以再次改变策略,(重点来了 下面是解决问题的思路)
第一要减少计算量,滑动回调密集要尽量少计算,减少不必要的计算量。
第二要减少渲染切换的频率,每次滑动都有商品在隐藏有商品在渲染,这也是很大的性能开销。
根据最新的思路开始从新规划
1 商品分组 每次分页加载的数据都要分组,每一百个商品 一组, 在商品信息中加个属性 group : 1 这样 前一百的商品 都是等于1 第100至200 就等于2 以此类推
2 记录当前所展示的分组 showGroup:[1] showGroup 最多可能有两个成员连续[0,1] 像这样
3 商品组件里面 根据 showGroup 进行判断 判断自己的 group 是不是在 showGroup 内 如果在正常渲染 否则 渲染有个空div 高度和商品的高度一样
准备工作完成 然后 优化计算 也很简单
当前屏幕距离顶部的高度 / 商品高度 / 100
大家好好想想 这样计算后 你就能得到 1.xxxxxxx 或是 2.xxxxxx 这就是所展示的分组
然后再计算一次
(当前屏幕距离顶部的高度 / 商品高度)- 100
这样就能知道渲染是的是当前的分组第几个商品 根据这个值来对比 小于15 showGroup 变成[0,1] (假设 showGroup 原本是[1] 也就是用户浏览在 第100-200 位置)如果大于85 就是 [1,2] 用这样的形式来预判用户滑动的方向形成了预加载的形式,无论用户怎么滑动都有商品可以浏览,而且最多还可以保障200条商品。
最后切记要对比 只有在 showGroup 不同的时候再去更新 showGroup 所以每次滑动只需计算两个公式 形成 数组和 showGroup 比较即可,也减少了计算量
这就是基本解决问题的思路。
总结 主要的解决思路就是 用div区块滚动 + 商品展示隐藏,每次只展示100个商品其余隐藏
最后在聊一聊与之相关的 不展示的商品隐藏 在制作的过程中 使用过 visibility:hidden 这样的属性,这样的好处是 可以不用换成div 设置和商品高度一样 解决了适配的问题因为有的屏幕小 不让页面跳动,对高度还是很严格的 但是 visibility:hidden 这个属性还是有些卡顿,没有直接变成一个简洁的div流程。
再说说为什么的选择 div区块滚动 因为这多少也算是原生的滚动性能还是蛮不错的,body肯定不能用,不满足业务场景,css3没有这个流程所以就选择了这个,而且也没有完全独立用自己写的 采用的是mescroll 框架 是一款很不错的解决下拉刷新 上滑加载的js框架 他内部采用的就是 div区块滚动 滑动头部根据手指滑动距离增加高度来实现的拉动效果,主要的是他采用div区块滚动所以整理来说很流畅。
好,想说的就是这些,以上是我遇到的问题以及解决思路。