vue实现虚拟列表
虚拟列表的概念
虚拟列表(Virtual List)是一种优化长列表渲染性能的技术,通过仅渲染可视区域内的元素,减少DOM节点数量,从而提升页面性能。适用于数据量大的场景(如表格、下拉选择器等)。
实现虚拟列表的核心步骤
计算可视区域高度和单个项高度
确定容器高度(clientHeight)和每个列表项的高度(固定或动态获取)。动态高度需通过测量或预估实现。

计算可见项范围
根据滚动位置(scrollTop)和可视区域高度,计算当前应渲染的起始索引(startIndex)和结束索引(endIndex):
- 起始索引:
Math.floor(scrollTop / itemHeight) - 结束索引:
Math.min(startIndex + visibleCount, totalItems - 1)
动态渲染可见项
通过v-for仅渲染可见项,并通过transform: translateY()偏移列表位置,模拟完整滚动效果。

滚动事件监听
监听容器的scroll事件,动态更新startIndex和endIndex,触发重新渲染。
Vue 实现示例代码
<template>
<div class="virtual-list" @scroll="handleScroll" ref="listContainer">
<div class="list-phantom" :style="{ height: totalHeight + 'px' }"></div>
<div class="list-content" :style="{ transform: `translateY(${offset}px)` }">
<div v-for="item in visibleData" :key="item.id" class="list-item">
{{ item.content }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
listData: [], // 所有数据
itemHeight: 50, // 每项高度(固定)
visibleCount: 0, // 可视区域可展示项数
startIndex: 0, // 起始索引
endIndex: 0, // 结束索引
offset: 0, // 偏移量
};
},
computed: {
totalHeight() {
return this.listData.length * this.itemHeight;
},
visibleData() {
return this.listData.slice(this.startIndex, this.endIndex);
},
},
mounted() {
this.initData();
this.calculateVisibleCount();
},
methods: {
initData() {
// 模拟生成大量数据
this.listData = Array.from({ length: 10000 }, (_, i) => ({
id: i,
content: `Item ${i}`,
}));
},
calculateVisibleCount() {
const containerHeight = this.$refs.listContainer.clientHeight;
this.visibleCount = Math.ceil(containerHeight / this.itemHeight);
this.endIndex = this.startIndex + this.visibleCount;
},
handleScroll() {
const scrollTop = this.$refs.listContainer.scrollTop;
this.startIndex = Math.floor(scrollTop / this.itemHeight);
this.endIndex = this.startIndex + this.visibleCount;
this.offset = scrollTop - (scrollTop % this.itemHeight);
},
},
};
</script>
<style>
.virtual-list {
height: 500px;
overflow-y: auto;
position: relative;
}
.list-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
}
.list-content {
position: absolute;
left: 0;
top: 0;
right: 0;
}
.list-item {
height: 50px;
line-height: 50px;
border-bottom: 1px solid #eee;
}
</style>
动态高度处理
若列表项高度不固定,需预先测量或估算高度,并维护一个位置映射表(如positions: { index: { top, height } })。滚动时通过二分查找确定startIndex和endIndex。
性能优化建议
- 防抖处理:对
scroll事件添加防抖(如requestAnimationFrame)。 - 缓冲区:额外渲染部分不可见项(如前后多渲染5项),避免快速滚动白屏。
- 复用DOM:使用
<template v-for>或第三方库(如vue-virtual-scroller)减少DOM操作开销。
第三方库推荐
通过上述方法或库,可高效实现虚拟列表,解决大数据量下的渲染卡顿问题。






