虚拟化列表vue实现
虚拟化列表的实现原理
虚拟化列表(Virtual List)通过仅渲染可视区域内的元素来优化长列表性能,减少DOM节点数量和内存占用。核心思路是根据滚动位置动态计算需要渲染的数据项,并调整列表项的偏移位置。
基于Vue的虚拟化列表实现步骤
计算可视区域范围
监听容器的滚动事件,获取当前滚动位置scrollTop和容器高度clientHeight,结合单个列表项高度itemHeight,计算出可视区域的起始索引和结束索引:

const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(clientHeight / itemHeight),
data.length
);
动态渲染可见项
根据计算得到的startIndex和endIndex,从完整数据中切片出需要渲染的部分,并通过CSS的transform属性控制列表偏移:

const visibleData = data.slice(startIndex, endIndex);
const offsetY = startIndex * itemHeight;
模板中通过v-for绑定visibleData,并设置容器的padding-top或transform模拟完整高度。
优化滚动性能
使用requestAnimationFrame节流滚动事件处理,避免频繁计算。对于可变高度的列表项,需额外维护位置缓存(如二分查找定位)。
示例代码实现
<template>
<div
class="virtual-list"
@scroll="handleScroll"
:style="{ height: `${clientHeight}px` }"
>
<div class="list-content" :style="{ height: `${totalHeight}px` }">
<div
v-for="item in visibleData"
:key="item.id"
class="list-item"
:style="{ height: `${itemHeight}px` }"
>
{{ item.content }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
data: [], // 完整数据源
itemHeight: 50,
clientHeight: 500,
startIndex: 0,
scrollTop: 0
};
},
computed: {
visibleData() {
const endIndex = this.startIndex + Math.ceil(this.clientHeight / this.itemHeight);
return this.data.slice(this.startIndex, endIndex);
},
totalHeight() {
return this.data.length * this.itemHeight;
},
offsetY() {
return this.startIndex * this.itemHeight;
}
},
methods: {
handleScroll(e) {
this.scrollTop = e.target.scrollTop;
this.startIndex = Math.floor(this.scrollTop / this.itemHeight);
}
}
};
</script>
<style>
.virtual-list {
overflow-y: auto;
}
.list-content {
position: relative;
}
.list-item {
position: absolute;
width: 100%;
transform: translateY(var(--offsetY));
}
</style>
第三方库推荐
- vue-virtual-scroller:提供
RecycleScroller和DynamicScroller组件,支持固定高度和动态高度。 - vue-virtual-scroll-list:轻量级实现,适用于简单场景。
- @tanstack/vue-virtual(原react-virtual移植):功能强大,支持横向虚拟化和自定义滚动行为。
性能优化注意事项
- 使用
key属性确保列表项复用。 - 避免在列表项内使用复杂的响应式数据。
- 对于动态高度,需预先测量或监听高度变化更新位置缓存。






