前端性能优化之虚拟列表学习笔记
前言
用来记录自己的学习过程,参考网上多篇文章,可能不太完整日后慢慢学习慢慢补充。
此篇介绍的是关于性能优化的虚拟列表部分。用vue来完成一个虚拟列表的简易实现。
一、虚拟列表是什么?
简单来说,虚拟列表值得就是【可视区域渲染】的列表。
在有大量数据需要展示在页面上时,通过监听用户的滚动事件,动态地只对可见区域进行渲染,对非可见区域不渲染,从而达到极高的渲染性能。
首先弄清楚两个概念,【可滚动区域】和【可见区域】。
- 可滚动区域:「 整个列表的数据量*每项列表的高度 」真实列表长度这部分区域。即需要展示的数据区域。
假设有 1000 条数据,每个列表项的高度是 30,那么可滚动的区域的高度就是 1000 * 30。当用户改变列表的滚动条的当前滚动值的时候,会造成可见区域的内容的变更。
- 可见区域:设定的列表的高度,用户可见的,需要动态渲染的区域。
二、用vue实现一个简单的虚拟列表
虚拟列表的实现,实际上就是在首屏加载的时候,只加载可视区域内需要的列表项,当滚动发生时,动态通过计算获得可视区域内的列表项,并将非可视区域内存在的列表项删除。
整体代码部分
<template>
<div>
<h1>虚拟列表学习</h1>
<!-- 使用虚拟列表 -->
<!-- 可视区域容器 监听scroll事件 -->
<div class="virtual" @scroll="scroll" :style="{ height: 400 + 'px' }">
<div class="list" :style="{ height: dataLengh * itemHeight + 'px' }">
<!-- 列表项的渲染区域 margin-top定位当前滚动的位置-->
<ul :style="{ 'margin-top': `${scrollTop}px` }">
<li
v-for="(item, index) in visiablelist"
:key="index"
:style="{ height: itemHeight + 'px' }"
>
{{ item }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import { reactive, toRefs, computed } from "vue";
export default {
setup() {
const dataLengh = 10000; // 列表数据量
const itemHeight = 40; // 列表每项高度
const data = reactive({
scrollTop: 0, // 当前滚动的位置
startIndex: 0, // 数据的起始索引
endIndex: 10, //数据的结束索引
});
function scroll(e) {
// 获取当前滚动的位置
const scrollTop = e.target.scrollTop;
data.scrollTop = scrollTop;
// 此时开始的索引
data.startIndex = Math.floor(scrollTop / itemHeight);
// 此时结束的索引
data.endIndex = data.startIndex + 10;
}
// 创建一个长数组
const list = new Array(dataLengh);
for (var i = 0; i < list.length; i++) {
list[i] = i ;
}
// 可视列表部分 从已有数组中返回选定的元素,返回一个子数组,即需要展示部分
const visiablelist = computed(() => {
return list.slice(data.startIndex, data.endIndex);
});
return {
...toRefs(data),
scroll,
visiablelist,
dataLengh,
itemHeight,
list
};
},
};
</script>
<style scoped>
.virtual {
border: solid 1px #eee;
height: 400px;
overflow:auto;
}
.list {
overflow: hidden;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
outline: solid 1px #fff;
}
</style>
总结
参考链接
再谈前端虚拟列表的实现:https://zhuanlan.zhihu.com/p/34585166.
「前端进阶」高性能渲染十万条数据(虚拟列表):https://juejin.cn/post/6844903982742110216#heading-3