一文搞懂虚拟列表
1.虚拟列表介绍
虚拟列表是一种用于优化大型列表渲染性能的技术。当你需要展示大量数据时,例如聊天记录、商品列表等,传统的渲染方式可能会导致性能问题,因为要同时渲染大量的DOM元素。
虚拟列表通过只渲染可见区域内的元素,从而减少DOM操作,提高渲染性能。以下是虚拟列表的基本工作原理和一些实现步骤:
- 确定容器高度: 首先,确定列表容器的高度,这将决定可见区域的大小。
- 计算可见元素: 基于容器高度,计算出可见区域内可以容纳的元素数量。这些元素将是实际渲染的元素。
- 渲染可见元素: 仅渲染可见区域内的元素,而不是整个列表。未在可见区域内的元素不会被创建或渲染。
- 虚拟滚动: 监听滚动事件,根据滚动位置动态更新可见区域内的元素。只有当用户滚动列表时,才进行实际的DOM操作。
人话描述:初次渲染一屏的dom项,然后每次滚动都细粒度到一项一项去渲染
思路:监听滚动事件,每一次滚动的时候都动态计算startIndex(起始索引) 和 startIndex(起始索引) + visibleItems(展示区可视区域可以容纳的项数)的值,然后可以利用v-for或者for循环去渲染!
以下是一个简单的虚拟列表实现示例,使用 JavaScript 和 HTML/CSS。在这个示例中,我们将使用一个包含大量数据的列表,并通过虚拟列表来优化渲染性能:
HTML:
<div class="container">
<ul class="list">
<!-- 这里不需要在初始状态渲染所有元素 -->
</ul>
</div>
CSS:
.container {
height: 300px;
overflow: auto;
}
.list {
padding: 0;
margin: 0;
}
JavaScript:
const container = document.querySelector('.container');
const list = document.querySelector('.list');
const itemHeight = 50; //每一项的高度
const totalItems = 1000; //总项数
const visibleItems = Math.ceil(container.clientHeight / itemHeight); //计算展示区可视区域可以容纳的项数(就是默认的基本渲染个数)
function renderItems(startIndex) {
const fragment = document.createDocumentFragment();
for (let i = startIndex; i < startIndex + visibleItems; i++) {
const item = document.createElement('li'); //创建dom,只创建和渲染对应需要展示的一部分,而不是已经加载的也去渲染
item.textContent = `Item ${i}`;
item.style.height = `${itemHeight}px`;
fragment.appendChild(item);
}
list.innerHTML = '';
list.appendChild(fragment);
}
container.addEventListener('scroll', () => {
const scrollTop = container.scrollTop;
const startIndex = Math.floor(scrollTop / itemHeight); //计算当前应该渲染第几项了(利用滚动的距离除以每个项的高度)
renderItems(startIndex); //只有滚动到相应的位置才渲染
});
// 初始渲染
renderItems(0); //0+默认的基本渲染个数
这个示例展示了如何创建一个基本的虚拟列表,当用户滚动列表时,它会动态地渲染可见区域内的元素,而不是一次性渲染所有元素。这可以有效地提高大型列表的性能,因为只有可见区域内的元素才会被渲染和操作。在实际应用中,还可以结合一些性能优化技巧,如对象池、动态加载等,以进一步提升虚拟列表的性能。
由于只渲染当前能看到的元素,理论上会出现没有滚动条的情况,那么就意味着无法监听滚动事件,所以我们如何把滚动条撑开呢?
在前面和后面都加一个空的div即可!把高度撑开,让内容区域的高度大于容器区域,就可以出现滚动条了!
2.虚拟列表展示和触底加载的区别?
虚拟列表展示和触底加载是两种不同的前端技术,用于处理大量数据的列表渲染和加载。它们的主要区别在于它们解决的问题和实现的方式。
- 虚拟列表展示: 虚拟列表展示是一种用于优化大型列表渲染性能的技术。当你需要展示大量数据时,传统的渲染方式可能会导致性能问题,因为要同时渲染大量的DOM元素。虚拟列表通过只渲染可见区域内的元素,从而减少DOM操作,提高渲染性能。这种技术通常会根据可见区域的大小和滚动位置,动态地渲染列表的子集,从而保持页面的性能。——> 相对于触底加载,最大的好处是每次滚动都细粒度到一项一项去渲染,并且只创建和渲染对应需要展示的一部分,而不是已经加载的也去渲染,而触底加载不行!其他的好处可能是不需要每次滚动都进行等待(因为按理来说也是一次性请求所有数据),而且还能优化加载速度
- 触底加载: 触底加载是一种处理无限滚动列表的方式,通常用于加载更多数据。当用户滚动到列表的底部时,会触发加载更多数据的操作,以实现无缝地加载更多内容,而不需要显式地点击“加载更多”按钮或进行其他操作。这对于需要加载大量数据的应用,如社交媒体的滚动式新闻加载、无限滚动列表等,非常有用。
**虚拟列表展示和触底加载通常可以结合使用,以实现更好的用户体验。**例如,在一个虚拟列表中,你可以使用触底加载来加载更多数据,从而逐步加载用户滚动到的下一页内容,而不是一次性加载所有数据。
综上所述,虚拟列表展示主要是为了优化大型列表的渲染性能,而触底加载主要用于处理无限滚动列表并实现动态加载数据。两者都是为了提高用户体验和减少不必要的性能开销。
3.在vue里面实现虚拟列表展示
在 Vue 中实现虚拟列表展示通常涉及以下步骤:
- 计算可见区域: 首先,你需要计算出可见区域内可以容纳多少个列表项,并计算每个列表项的高度。
- 创建虚拟列表容器: 创建一个固定高度的容器,用于显示可见区域内的列表项。这个容器可以使用 CSS 样式来设置高度和样式。
- 动态渲染列表项: 使用
v-for
指令渲染虚拟列表容器中的列表项。根据可见区域的高度和列表项的高度,动态计算要渲染的列表项数量和位置,并将其渲染到容器中。 - 监听滚动事件: 监听虚拟列表容器的滚动事件,以获取滚动位置,然后根据滚动位置动态计算可见区域内要渲染的列表项。
下面是一个简单的示例,演示了如何在 Vue 中实现虚拟列表展示:
<template>
<div class="virtual-list" ref="listContainer" @scroll="handleScroll">
<div class="virtual-list-item" v-for="(item, index) in visibleItems" :key="index">
{{ item }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
totalItems: 1000, // 总列表项数量
itemHeight: 50, // 列表项高度
visibleItems: [] // 可见区域内的列表项
};
},
methods: {
handleScroll() {
const container = this.$refs.listContainer;
const scrollTop = container.scrollTop;
const startIndex = Math.floor(scrollTop / this.itemHeight);
this.updateVisibleItems(startIndex);
},
updateVisibleItems(startIndex) {
const endIndex = Math.min(startIndex + this.visibleItemCount, this.totalItems); //取totalItems和总共的其中的较小的,防止总数不够
this.visibleItems = this.allItems.slice(startIndex, endIndex); //滚动到相应位置后,从所有数据中截取一部分(只渲染对应需要展示的一部分,而不是已经加载的也去渲染),作为visibleItems来v-for渲染
}
},
computed: {
visibleItemCount() {
return Math.ceil(this.$refs.listContainer.clientHeight / this.itemHeight);
},
allItems() {
// 生成所有列表项的数据,例如使用循环生成,实际应该是从后端ajax请求
return Array.from({ length: this.totalItems }, (_, index) => `Item ${index}`);
}
},
mounted() {
this.updateVisibleItems(0); // 初始渲染
}
};
</script>
<style>
.virtual-list {
height: 300px;
overflow: auto;
}
.virtual-list-item {
height: 50px;
line-height: 50px;
border-bottom: 1px solid #ccc;
text-align: center;
}
</style>
在这个示例中,我们创建了一个虚拟列表容器,根据滚动位置动态计算可见区域内要渲染的列表项,并将其渲染到容器中。这是一个基本的示例,你可以根据实际需求进行定制和优化。