vue虚拟滚动性能优化方式详解

目录

引言

虚拟滚动(Virtual Scrolling)

理解虚拟滚动

虚拟

滚动

实现虚拟滚动

核心步骤

效果预览

最后

引言

一个简单的情景模拟(千万别被带入):

A: 假设现在有 10 万条数据,你作为前端该怎么优化这种大数据的列表?

B: 针对大数据列表一般不会依次性加载,会采用上拉加载、分页加载等方式实现优化.

A: 那假如加载到最后一条数据的时候,页面上只是列表部分的数据就至少对应 10 万个 dom 节点,你觉得一个页面渲染至少 10 万个 dom 节点的性能如何?

A: 如果这样的列表有 n 个呢?还有没有别的优化方式?

B: 要不我把自己优化一下 ......

其实解决上述问题就可以使用 虚拟滚动 来实现优化,相信大家对这个词都不陌生,但由于这个名词比较短(又是虚拟,又是滚动)导致很多人觉得这是非常高大上、难以理解的内容,但其实恰恰相反。

本文的目的就是帮助你以 最简单 的方式 理解虚拟滚动,甚至实现 虚拟滚动.

虚拟滚动(Virtual Scrolling) 理解虚拟滚动

其实要理解 虚拟滚动 这个词很简单,按照 虚拟 和 滚动 两部分来理解就很简单了,下面就一一拆解。

虚拟

通常在页面列表中,要渲染的 列表数量 和真实在文档中存在的 DOM 节点数 是 1 : 1 的。

每个列表项都拥有相同的高度(假设是 30px),这个列表容器中需要完全渲染的列表数(假设是 100 条)和在页面中的高度是一致的,即此时的高度就为 100 * 30 = 300 px,对应列表的 DOM 数量为 100,如:

对于 虚拟滚动 来讲,虚拟 的意思是指实际要渲染完整列表对应的高度是通过 虚拟计算 的,并不是指文档中存在对应的 DOM 节点数。

上面的栗子对应到虚拟滚动来讲,就意味着实际渲染完整列表对应的高度就仍为 100 * 30 = 300px,但实际渲染数就变为 10 条,关系图大致如下:

滚动

所谓 滚动 就很好理解了,因为列表可视区通常会限制一定的高度,即 列表可视区高度,那么此时只要 虚拟列表高度 值大于 列表可视区高度 时,就会产生滚动条即可发生滚动操作。

值得注意的是,在发生滚动时需要对 实际渲染的列表 进行一些处理,否则会出现 实际渲染的列表 和 虚拟列表区 脱离的情况,比如:

关键点就是实现在发生 滚动 操作时,保证 实际渲染的列表 一直存在 列表可视区 中,并且动态切换需要渲染的列表数据。

实现虚拟滚动 核心步骤

设置列表可视区的高度 containerHeight

设置单个列表项的高度 listItemHeight

计算渲染完整列表需要的高度 virtualHeight,即 virtualHeight = listItemHeight * data.length

设置真实渲染数据的起始索引 startIndex、endIndex,用于从列表数据 data 中获取对应的数据内容

注册/监听滚动事件 onScroll获取当前实际滚动距离 eleScrollTop

将 eleScrollTop 作为 translateY 的值,即 实际渲染列表元素 平移的数值,保证 实际渲染列表元素 一直存在可视区中

根据实际的滚动距离 eleScrollTop,动态计算列表新的起始索引 startIndex、endIndex

效果预览

具体实现细节都在如下的代码中,可结合其中的注释阅读:

// App.vue <script> const list = (num = 10)=> { const data = []; for (let i = 0; i < num; i++) { data.push({ id: i+1, name: `第 ${i+1} 条列表` }); } return data; } </script> <template> <VirtualScroll :data="list(100)" /> </template> // VirtualScroll.vue <template> <!-- 虚拟滚动内容 --> <div class="virtual-scroller" @scroll="onScroll" :style="{ height: containerHeight + 'px' }" > <!-- 实际渲染的列表内容 --> <ul class="real-list-content" :style="{ transform: `translateY(${tranlateY}px)` }" > <li v-for="item in visibleList" :key="item.id" :style="{ height: `${listItemHeight}px`, 'line-height': `${listItemHeight}px`, }" > <div>{{ item.name }}</div> </li> </ul> <!-- 虚拟列表元素 --> <div class="virtual-height" :style="{ height: virtualHeight + 'px' }"> ~ 数据加载完毕 ~ </div> </div> </template> <script> export default { name: "vue-virtual-scroll", }; </script> <script setup language="ts"> import { computed, ref } from "vue"; const props = defineProps({ data: { type: Array, default: [], }, startIndex: { type: Number, default: 0, }, endIndex: { type: Number, default: 10, }, listItemHeight: { type: Number, default: 60, }, containerHeight: { type: Number, default: 500, }, }); let { data, listItemHeight } = props; const tranlateY = ref(0); // 平移距离 const startIndex = ref(props.startIndex); // 开始索引 const endIndex = ref(props.endIndex); // 结束索引 // 实际渲染的数据 const visibleList = computed(() => { return data.slice(startIndex.value, endIndex.value); }); // 虚拟滚动的高度 const virtualHeight = computed(() => { return (data.length - visibleList.value.length) * listItemHeight + listItemHeight; }); // 滚动事件 const onScroll = (e) => { const eleScrollTop = e.target.scrollTop; // 保证实际渲染列表一直停留在可视区 tranlateY.value = eleScrollTop; // 根据实际的滚动距离,动态计算列表开始索引 startIndex.value = Math.floor(eleScrollTop / listItemHeight); // 基于开始索引 endIndex.value = startIndex.value + 10; }; </script> <style scoped> .virtual-scroller { border: solid 1px #eee; margin-top: 10px; height: 600px; overflow: auto; } .virtual-height { background: red; display: flex; align-items: end; justify-content: center; color: #fff; } ul { list-style: none; padding: 0; margin: 0; } li { outline: solid 1px #fff; background-color: #000; color: #fff; } </style> 最后

其实 虚拟滚动 并不难理解,就像 CSS 中的 BFC、JavaScript 中的闭包 等概念一样,最初了解时你很难给它一个定义,但是实际上下功夫去了解它,其实也就那么一回事。

以上的实现方式是极简的方式,没有做任何的优化、没有考虑额外的场景,因为本文的目的还是想通过最简单的实现去解释虚拟滚动到底是怎么一回事,因此不必过于纠结,当然在 vue 中早已有了相关库的实现 vue-virtual-scroller 可自行了解,更多关于vue虚拟滚动性能优化的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读

    提高3A四核羿龙II游戏配置的性能

    提高3A四核羿龙II游戏配置的性能,,以节能环保为主题的IT产业,目前3A低端平台处理器、主板芯片组、独立开发卡性能突出,特别是在与AMD的处理

    3500元超额值学生娱乐结构的优化配置

    3500元超额值学生娱乐结构的优化配置,,作为一个DIY的主流用户领域的学生,每个用户51学生攒机的高峰。因为学生用户没有稳定的收入来源,攒机

    优化PostgreSQL中的批量更新性能

    优化PostgreSQL中的批量更新性能,数据,表格,在Ubuntu 12.04上使用PG 9.1. 我们目前需要24小时才能运行大量UPDATE数据库上的语句,其形式

    诺基亚威图性能好到哪里

    诺基亚威图性能好到哪里,诺基亚,手机,诺基亚威图性能好到哪里这是一部以前列出的手机。即使当时配置不高,该品牌的手机也不依赖于该功能吸

    魅蓝note6性能参数有哪些

    魅蓝note6性能参数有哪些,摄像头,蓝牙,魅蓝note6性能参数有哪些魅力蓝色Note6最好拍照。电池寿命更长。蓝色Note6使用高通 snapdragon 625

    512内存的电脑优化|笔记本内存512

    512内存的电脑优化|笔记本内存512,,1. 笔记本内存512够用,因为运行非常流畅,苹果笔记本 16g512的运行内存是16g内存,机身内存是512g内存,运行

    Windows7下固态硬盘的优化技术

    Windows7下固态硬盘的优化技术,,当微软开发Windows Vista时,固态硬盘没有那么热,所以没有进行优化。Windows 7是不同的。微软从一开始就把SS

    国产电脑cpu测试|国产CPU性能

    国产电脑cpu测试|国产CPU性能,,国产CPU性能天玑9000答: 天玑9000更厉害。因为天玑9000是 最新发布的cpu,也是现在的天花板。而麒麟9000是 2

    主流电脑cpu性能分析|cpu性能对比表

    主流电脑cpu性能分析|cpu性能对比表,,1. cpu性能对比表一、参数对比1、r7 5800H:制程工艺为7nm,主频3.2GHz,睿频4.4GHz,线程数是8核16线程,45W

    新老酷睿i3性能对比试验i34130和i33220

    新老酷睿i3性能对比试验i34130和i33220,,新的英特尔酷睿i3-4130 Haswell处理器架构已经推出了很长一段时间,虽然市场的时间还不长,已经成为