前言🎀
在前文中我们了解到:
1.在某种特殊场景下,我们需要将 大量数据 使用不分页的方式渲染到列表上,这种列表叫做长列表。
2.因为事件循环的机制,一次性大量的渲染耗时较长,并且渲染期间会阻塞页面交互事件,所以我们使用时间分片机制将渲染分为多次。
3.分析真实业务场景,将全部数据渲染到列表中是无用且浪费资源的行为,只需要根据用户的视窗进行部分渲染即可,所以使用到虚拟列表技术。
前文中我们根据 “无论滚动到什么位置,浏览器只需要渲染可见区域内的节点” 的思路实现了虚拟列表解决了长列表问题,但在一些细节和特殊情况的处理上还是有所欠缺,例如:
1.高度不定的列表项会导致内容出现错位、偏移等情况。
2.列表项含有异步资源,会在渲染后再次改变高度。
3.一次性大量数据的请求导致请求响应与数据处理时间过长。
在本文中我们就来一起研究这些场景,并对原版的虚拟列表做出优化 🚀
如果觉得有收获还望大家点赞、收藏 🌹
动态高度
分析
在前文的虚拟列表实现中,列表项高度itemSize
都是固定的。
// template -> list-item
:style="{ height: itemSize + 'px', lineHeight: itemSize + 'px' }"
// export defualt -> data
itemSize: 50,
因此很多直接与 列表项高度itemSize
关联的属性,都很容易计算:
1.列表总高度listHeight
= listData.length * itemSize
2.当前窗口偏移量currentOffset
= scrollTop - (scrollTop % itemSize)
3.列表数据的开始/结束索引start/end
= ~~(scrollTop / itemSize). . . . . .
但在实际情况中列表元素多为高度不固定的列表项,它可能是多行文本、图片之类的可变内容,如系统日志、微博等等。
不固定的高度会导致上述的属性无法正常计算。
对于高度不固定的列表项,我们遇到的问题如下:
1.如何获取真实高度?
2.相关的属性该如何计算?
3.列表渲染的方式有何改变?
方案
如何获取真实高度?
-
如果能获得列表项高度数组,真实高度问题就很好解决。但在实际渲染之前是很难拿到每一项的真实高度的,所以我们采用预估一个高度渲染出真实DOM,再根据DOM的实际情况去设置真实高度。* 创建一个缓存列表,其中列表项字段为 索引、高度与定位,并预估列表项高度用于初始化缓存列表。在渲染后根据DOM实际情况更新缓存列表。相关的属性该如何计算?
-
显然以前的计算方式都无法使用了,因为那都是针对固定值设计的。* 于是我们根据缓存列表重写 计算属性、滚动回调函数,例如列表总高度的计算可以使用缓存列表最后一项的定位字段的值。列表渲染的方式有何改变?
-
因为用于渲染页面元素的数据是根据 开始/结束索引 在 数据列表 中筛选出来的,所以只要保证索引的正确计算,那么渲染方式是无需变化的。* 对于开始索引,我们将原先的计算公式改为:在 缓存列表 中搜索第一个底部定位大于 列表垂直