前言:最近在开发一个通用组件排行榜的时候,需要展示多条数据,数据量虽然不大,但是开发的组件需要嵌入到PC、安卓、IOS多端适配。适配的时候需要处理一下这些数据量,不然会产生性能问题。然后在浏览谷歌的时候就发现虚拟列表这个东西

虚拟列表

  • 虚拟列表是指对列表的 可视区域 进行渲染,对 非可见区域 不渲染或部分渲染,从而极大提高渲染性能的一种技术。

相关库

  • 目前我觉得比较好用的库是**vue-virtual-scroller**
  • 此外还有vue*-*virtual-scroll-list、react-virtualized等

Vue-Virtual-Scroller的使用

安装

1
2
3
4
5
npm install --save vue-virtual-scroller@next

yarn add vue-virtual-scroller@next

npm install --save vue-virtual-scroller@next --legacy-peer-deps

在main.js中全局使用

1
2
3
4
5
6
7
import { createApp } from 'vue';
import VueVirtualScroller from 'vue-virtual-scroller';
import App from './App.vue';

const app = createApp(App)
app.use(VueVirtualScroller)
app.mount('#app')

RecycleScroller组件

  • 使用该组件的时候,需要给定每个item的高度
  • 而DynamicScroller组件,则是不需要知道item的高度,自动计算其值
  • 首先在需要使用的组件中引入 ↓
1
2
import { DynamicScroller } from 'vue-virtual-scroller';
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
  • 然后直接使用即可,有几个props需要在使用的时候传入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<template>
<div class="reyclerList">
<RecycleScroller
style="height: 100%;"
v-if="list.length > 0"
:items="list"
:item-size="50"
key-field="id"
:minItemSize="0"
:buffer="200"
v-slot="{ item , index }"
>
<div>{{ index }} :{{ item.nums }}}</div>
</RecycleScroller>
</div>
</template>

<script>
import { RecycleScroller } from 'vue-virtual-scroller';
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
export default {
components: {
RecycleScroller
},
setup() {
const list = []
for(let i = 0; i < 10000; i++) {
list.push({
id: i,
nums: `list-nums ${i}`
})
}

return {
list
}
}
}
</script>

<style>
.reyclerList{
width: 100%;
height: 600px;
}
</style>
  • 效果

  • 可以看到,使用了RecycleScroller加载1万条数据,只会渲染部分dom,而不会全部加载出来,通过这种方式可以减少dom的加载,极大优化性能

DynamicScroller组件

  • DynamicScroller和RecycleScroller差不多,但是它可以不

相关props传参

  • items: 要在滚动条中显示的总列表。
  • direction (default: 'vertical'): 滚动的方向,列表的方向,有垂直和水平,默认是垂直方向, 'vertical' or 'horizontal'.
  • itemSize: 子列表的高度,默认为null,在RecycleScroller中必须要设置这个
  • minItemSize: 如果子列表的高度(或水平模式下的宽度)未知,则使用最小尺寸。
  • keyField: 默认是是id,列表循环的key值,一般这个也是必传的
  • buffer: 默认是200,到滚动可见区域的边缘以开始渲染更远的项目的像素量。默认是上下200px处的都会进行缓存渲染
  • emitUpdate: 默认是false,表示是否要开启更新模式,官方描述:触发一个 'update' 时间,一般会配合钩子函数update一起使用

相关Events,钩子函数

  • update (startIndex, endIndex, visibleStartIndex, visibleEndIndex): 每次滚动的时候,当可使区域发生变化,触发该钩子函数的方法,仅当props——emitUpdate 为true的时候生效
  • scroll-start: 当第一个item渲染完的时候触发
  • scroll-end: 当最后的一个item渲染完的时候触发

插槽slot

  • item: 可视区域的item
  • index: item的下标
  • active: 可视活动状态下的item

虚拟列表的原理

  • 这里参考了掘金大佬的图,可以很好的解释了虚拟列表的原理

  • 简单来说就是在滚动的时候,让上面和下面的item通过transform向上平移,这样做就可以只渲染少量的dom,减少不必要真实dom的渲染。
  • 监听滚动
  • 需要知道item的高度,每次滚动对每个item进行transform计算
  • 根据滚动的距离和item的高度,计算出startIndex
  • 再根据startIndex和可视区高度计算出endIndex
  • 滚动时候,计算出可视区列表的偏移距离 startOffset,再重新计算startIndexendIndex

手写虚拟列表

…待更