【js】咱们须要无限滚动列表吗?

  无限滚动列表,顾名思义,是可以无限滚动的列表(愿意是指那些可以不断缓冲加载新数据的列表的)。可是,咱们真的须要这样一个列表吗?在PC端,浏览器的性能其实已经可以知足海量dom节点的渲染刷新(笔者通过简单的测试,1w+的节点并无很明显的卡顿),可是一样的dom数量在移动端却不行,在dom结构合理的状况下,可以保持在2K+的dom数量已经是一个很不错的列表了,可是dom数量再进一步增长就会明显影响页面的渲染效率,也正由于此缘由,才有了此文关于无限列表的一些思考和探索。react

  首先,为何会卡顿?由于dom数量的绝对值上的不断增多,在后续的交互上(如滚动,局部更新)都会致使页面渲染性能的降低。ios

  那么,应该如何解决?既然是dom数量过多引发的,最简单也最有效的方法天然是减小dom数量。在jQuery时代,笔者便见过一种思路(其实本质实现至今也没有太大的变化):git

  一、只渲染特定几屏的数据,将多余的数据缓存在内存中,并不直接实例化到dom tree上,减小dom的绝对数量;github

  二、监听滚动事件,在滚动的时候动态的更新dom,让用户在视觉上看不出区别;api

  jQuery的实现因为年代久远,已经找不太到了,不过笔者在react社区找到了一个比较好的实现:react-virtualized,值得一提的是,它还将咱们的滚动场景区分为了viewport内的局部滚动,和基于viewport的滚动,前者至关于在页面中开辟了一块独立的滚动区域,属于内部滚动(和iscroll的滚动很相似,顺带一提iscroll也给出了iscroll-infinite的解决方案);然后者则把滚动做为了window滚动的一部分(对于移动端而言,在非模态窗的场景下这种滚动更常见,共用一个滚动条也不容易引发用户的误操做)。由于笔者主要的使用场景是后者,而iscroll的解决方案虽然也能做用于页面维度的滚动,可是它须要彻底替换scroll事件(至关于页面没有了scroll事件,只有touchmove事件;且此种页面在内部滚动和全局滚动的实现上有不小的难度),因此笔者在无限滚动列表上并无使用iscroll的方案。浏览器

  不过,业内虽然有现成的解决方案当然是好事,可是每种方案都有本身的特性,并不必定都合适,以react-virtualized来讲,它的特性在pc上算是一个颇有趣也很不错的解决方案了:缓存

  一、它构造一个“足够大”的容器来再现滚动条的实际数值;dom

  二、它使用绝对定位来不断跟随滚动事件,改变元素的位置,几乎完美还原了正常列表的视觉,并且不管dom再多也不会卡顿;性能

  不过,与此同时,它也有一些不足:测试

  一、由于使用了scroll事件,某种程度上,就注定了在ios上的不足(ios scroll时会阻塞js执行),加上它的缓冲区实际上是单向的(虽然这也体现了做者想尽量节省dom的愿景),致使用户若是上下来回滚动,则很容易看到白屏;

  二、因为绝对定位的“小技巧”,它要求在组件渲染之初就必须知道每一行元素的高度,可是这个看起来不起眼的小操做,却很大的影响了开发的体验(很不凑巧的笔者使用的无限列表的场景,不少状况下列表元素的高度都不能预先知道。。)

  也基于以上缘由,虽然react-virtualized是很不错的解决方案了,可是笔者最终没有采用。不过,在普遍借鉴了各大厂的实现以后,笔者发现,手淘列表页的实现,最简单也最有效,那么简单说下实现思路:

  一、它引入了分页的概念,在用户不断刷新增长页面长度的同时,它将若干元素分为一页;

  二、而后在滚动的时候计算当前滚动到了具体的哪一页,将“多余”(不须要显示,也不须要做为缓冲显示)的页的高度取出,直接赋值在容器上,而后将容器内全部元素置空;

  三、当“当前页”发生变化时,动态将须要显示“空页”从新加上元素。

  其实这一解决方案也有反复操做dom的性能问题,并且它并非dom数量优化上的最优解,可是结合笔者的实际使用场景,并且结合考虑到对业务同窗的api友好等各方面的,笔者最终也选择了这一实现,虽然各方面性能不是最好,可是在笔者当前的使用场景中,却最是有效的。

  简单的小结一下,其实有关无限列表的实现有不少种方案,使用原生scroll事件的痛点在于ios的js阻塞问题以及如何巧妙的设计缓冲区,而使用transform模拟滚动的痛点则是有具体场景的限制和总体的重构成本,两种方案各有千秋,具体使用还须要看具体的使用场景,因此,聪明的你,告诉我?咱们须要无线滚动列表么?

相关文章
相关标签/搜索