携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
使用场景与卡顿原因
日常开发过程中,经常接到一些需求,比如导入几千条的表格在前端显示并操作,或者后端接口没有分页一次返回几千条数据进行显示这种场景,如果我们不针对数据进行处理,直接把数据显示在页面中,我们会发现页面加载的时间会非常的慢,而且进行操作时会非常的卡顿,我们知道,js的处理速度是非常快的,而浏览器渲染节点的时候,会进行很多的图层绘制与计算,而从导致卡顿,我们可以针对这个问题,进行优化,提升交互体验。
方式一:时间切片(简单场景)
- 时间切片的主要原理是,用一个递归执行的函数完成数据的添加,当我们每次把当前部分数据加载到页面上以后,把下一次要添加的数据放到下一个宏任务执行,直到所有数据加载完为止。
- 时间切片主要使用了2个关键的api,
window.requestAnimationFrame与document.createDocumentFragment()。 - 其中
requestAnimationFrame的作用是会把每一帧所有操作集中起来,在一次重绘或回流中完成,间隔时间会紧跟浏览器的刷新频率(一般是1/60s)。(setTimeout渲染时机与浏览器刷新频率不一致,会导致闪现白屏) createDocumentFragment()可以创建一个虚拟的节点对象。提取文档的一部分,改变,增加,或删除某些内容及插入到文档末尾都可以使用此方法。由于文档片段存在于内存中,并不在dom树中,所以将子元素插入到文档片段时不会引起页面回流,会有更好的性能
方式二:虚拟列表(适用复杂场景)
- 虚拟列表使用3个节点即可完成,外面是一个固定高度的容器,内部创建一个真实高度(行高*数据长度)用于滚动的背景,同一层再创建一个用于显示的节点。
<div> <!-- 外部容器 -->
<div></div> <!-- 真实高度(背景用) -->
<div></div> <!-- 显示的节点/容器 -->
</div>
- 我们监听外部容器的滚动事件,可以获取到
scrollTop(滚动条距离顶部的高度),通过每行的行高,我们可以得出一个开始与结束的索引,使用scrollTop - (scrollTop % itemSize)动态计算出偏移量 - 实际列表可以用
list.slice(start, end)索引开始与结束截取显示 - 由于列表是会往上面滚动的,所以我们需要拿最新的索引,给显示的容器动态的设置style,进行对准
translate3d(0,${startOffset}px,0)
总结
- 时间切片一般用于简单场景,比如下拉框,或者纯文字展示的列表
- 虚拟列表简单复杂场景都可以使用,比如复杂的table,下拉框都可以使用,性能相比较时间切片更好。
下一章我们将会使用虚拟列表,结合基于vue,对element-ul的table进行一个改造,敬请期待吧