1.0.0-beta.16 • Published 3 years ago

@vb_he/vue-virtual-scroll v1.0.0-beta.16

Weekly downloads
-
License
-
Repository
github
Last release
3 years ago

背景

在项目中遇到渲染列表过大,导致页面卡顿问题;找了一下目前虚拟列表的插件,要么性能不佳,要么场景有限不能符合需求,所以考虑自己实现一个虚拟列表滚动的组件;主要是参考谷歌关于无限滚动的文章实现; 目前版本功能和特点如下:
1、仅支持垂直方向虚拟滚动;
2、仅支持数据一次性传递到组件;
3、支持异步渲染(监听元素变化,e.g. 图片渲染前和渲染后);

性能测试结果

demo 测试 5 万条数据在 chrome 下测试结果,基本保持在 60fps,内存消耗在 20m-50m 之间。

example

yarn && cd example && yarn && yarn serve

usage

npm i @vb_he/vue-virtual-scroll

难点

1 如何计算 item 高度并顺序给每个元素顺序叠加;

// 1 顺序通过不显示元素渲染得到item高度后加入到item数据中(通过eventloop事件优先级使用setTimeout计算item渲染后的宽高);

2 性能;

// 1 首次渲染两屏,滚动过程中渲染过逐渐增加到三屏数据(当前屏幕前后各一屏,当前一屏),保证当前显示内容始终保持是中间屏数据;
// 2 每次获取到元素宽高后,即更新数据,由框架处理渲染;
// 3 通过脱离文档流postion:absolute进行布局,避免大量重排导致性能下降;
// 4 不做无用的渲染(未得到宽高/位置的元素不渲染到列表数据中)
// 5 通过节流监听浏览器滚动事件;

3 滚动任务可能会在未渲染完成之前堆叠导致计算异常,需要通过队列控制渲染顺序;

问题记录

1、首屏渲染数据数量;
暂时考虑在两屏左右,由开发者配置,在不影响性能的前提下初始可以多渲染一些数据;

2、滚动时候加载更多数据的时机;

方案1: 监听滚动事件(防抖), 计算已滚动的item数量,补充&回收 dom;
方案2: 监听滚动事件,如果滚动到某个临界值(例如滚动了多少个数据/滚动了一定的距离), 则进行 补充&回收 数据;

方案2太多定制内容(滚动数据数量变化,临界值处理),容易出现问题。方案 1 可能会出现性能问题(但考虑到 google 也是用这个方案,并没有出现性能问题),所以采用方案 2;

3、被回收的数据如何恢复并重新渲染;
首先数据要保证是完整的,只有 dom 是被回收的,在 dom 上标记一个 index,通过 index 快速查询到需要渲染的数据;

4、如何计算滚动的 item 数量,在滚动后如何计算应该补充哪些数据(上下滚动), 多少数据?回收多少数据? 设置一个公式,以滚动条位置的 item 为分界,item 上方(上下滚动)显示元素数量为开发者初始渲染数据(后面以 N 替代)的 1/2,下方为 N-1.根据这个公式对数据进行补充/回收。临界状态(初始化上方数据未 0,底部数据无补充)特殊处理。 另, 因为 item 是在变化的,所以补充/回收的操作必须是等数据渲染完毕后进行。

5、如何计算滚动 item 的高度? 通过 item 数据将元素先渲染为不可见元素,渲染后通过 nexttick 获取到宽高。另外需要进行 dom 事件监听(MutationObserve,如果有变化再更新当前显示元素的位置);

性能问题记录

1 关于深拷贝;
一直没留意深拷贝的性能问题,但这次数据量比较大,问题就凸显了。当用 lodash 的 cloneDeep 拷贝一个两万条数据的数组时候(不只是简单类型的数组元素),耗时大概是 220ms,即使用 JOSN.parse(JSON.stringify())也需要 180ms 左右(称赞下 lodash 优化做的很好了). 之前比较习惯在处理完数据后再赋值给 vue 绑定的数据进行渲染,一个是不用经过多次渲染,一次渲染完成。但其实框架是有自己做优化,例如 vue 某个时间周期内多次数据变化会合并为一次渲染(后面在 vue 文档补充),react 的 setState 合并渲染;但也延伸了另外的问题,e.g. vue 无法监听到通过下标修改的数组元素变化,只能通过一些 trick 方式来修改,例如修改一个数组元素的时候,通过 splice 方式替换;
结论是当数据量很大而且对性能要求比较高的时候,尽量不要使用深拷贝。

更新记录

2022-07-25:

1、用 intersectionObserve 替代滚动条事件监听;  
2、异步监听"滚动元素",当元素发生变化时,实时更新滚动尺寸;  

参考

1 Complexities of an Infinite Scroller:https://developers.google.com/web/updates/2016/07/infinite-scroller
2 react-infinite-scroller: https://github.com/danbovey/react-infinite-scroller
3 react-infinite-scroll-component: https://github.com/ankeetmaini/react-infinite-scroll-component
4 动态生成 DOM 元素的高度及行数获取与计算方法: https://segmentfault.com/a/1190000004956121

1.2.4-beta.1

2 years ago

1.2.3

2 years ago

1.2.0

2 years ago

1.2.2-beta.1

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.1.5

2 years ago

1.1.4

2 years ago

1.2.1-beta.1

2 years ago

1.2.1-beta.2

2 years ago

1.2.1-beta.3

2 years ago

1.2.0-beta.1

2 years ago

1.2.0-beta.3

2 years ago

1.2.0-beta.2

2 years ago

1.1.1-beta.1

2 years ago

1.1.1

2 years ago

1.1.3

2 years ago

1.1.2

2 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago

1.0.5

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.1.0

3 years ago

1.0.0-beta.86

3 years ago

1.0.0-beta.84

3 years ago

1.0.0-beta.85

3 years ago

1.0.0-beta.82

3 years ago

1.0.0-beta.83

3 years ago

1.0.0-beta.80

3 years ago

1.0.0-beta.81

3 years ago

1.0.0-beta.77

3 years ago

1.0.0-beta.78

3 years ago

1.0.0-beta.75

3 years ago

1.0.0-beta.76

3 years ago

1.0.0-beta.74

3 years ago

1.0.0-beta.79

3 years ago

1.0.0-beta.70

3 years ago

1.0.0-beta.66

3 years ago

1.0.0-beta.22

3 years ago

1.0.0-beta.67

3 years ago

1.0.0-beta.23

3 years ago

1.0.0-beta.64

3 years ago

1.0.0-beta.20

3 years ago

1.0.0-beta.65

3 years ago

1.0.0-beta.21

3 years ago

1.0.0-beta.62

3 years ago

1.0.0-beta.63

3 years ago

1.0.0-beta.60

3 years ago

1.0.0-beta.61

3 years ago

1.0.0-beta.28

3 years ago

1.0.0-beta.29

3 years ago

1.0.0-beta.26

3 years ago

1.0.0-beta.27

3 years ago

1.0.0-beta.68

3 years ago

1.0.0-beta.24

3 years ago

1.0.0-beta.69

3 years ago

1.0.0-beta.25

3 years ago

1.0.0-beta.55

3 years ago

1.0.0-beta.11

3 years ago

1.0.0-beta.56

3 years ago

1.0.0-beta.12

3 years ago

1.0.0-beta.53

3 years ago

1.0.0-beta.54

3 years ago

1.0.0-beta.10

3 years ago

1.0.0-beta.51

3 years ago

1.0.0-beta.52

3 years ago

1.0.0-beta.50

3 years ago

1.0.0-beta.19

3 years ago

1.0.0-beta.17

3 years ago

1.0.0-beta.18

3 years ago

1.0.0-beta.15

3 years ago

1.0.0-beta.16

3 years ago

1.0.0-beta.57

3 years ago

1.0.0-beta.13

3 years ago

1.0.0-beta.44

3 years ago

1.0.0-beta.45

3 years ago

1.0.0-beta.42

3 years ago

1.0.0-beta.43

3 years ago

1.0.0-beta.40

3 years ago

1.0.0-beta.41

3 years ago

1.0.0-beta.48

3 years ago

1.0.0-beta.49

3 years ago

1.0.0-beta.46

3 years ago

1.0.0-beta.47

3 years ago

1.0.0-beta.2

3 years ago

1.0.0-beta.3

3 years ago

1.0.0-beta.4

3 years ago

1.0.0-beta.5

3 years ago

1.0.0-beta.1

3 years ago

1.0.0-beta.33

3 years ago

1.0.0-beta.34

3 years ago

1.0.0-beta.31

3 years ago

1.0.0-beta.32

3 years ago

1.0.0-beta.73

3 years ago

1.0.0-beta.6

3 years ago

1.0.0-beta.30

3 years ago

1.0.0-beta.7

3 years ago

1.0.0-beta.71

3 years ago

1.0.0-beta.8

3 years ago

1.0.0-beta.72

3 years ago

1.0.0-beta.9

3 years ago

1.0.0-beta.39

3 years ago

1.0.0-beta.37

3 years ago

1.0.0-beta.38

3 years ago

1.0.0-beta.35

3 years ago

1.0.0-beta.36

3 years ago

0.2.0

4 years ago

0.1.0

4 years ago