vue虚拟滚动列表实现
Vue 虚拟滚动列表实现方法
虚拟滚动(Virtual Scrolling)通过仅渲染可见区域内的元素来优化长列表性能,减少 DOM 节点数量。以下是 Vue 中实现虚拟滚动的几种方案:
使用第三方库(推荐)
-
vue-virtual-scroller
安装依赖:npm install vue-virtual-scroller示例代码:
<template> <RecycleScroller class="scroller" :items="list" :item-size="50" key-field="id" > <template v-slot="{ item }"> <div class="item">{{ item.name }}</div> </template> </RecycleScroller> </template> <script> import { RecycleScroller } from 'vue-virtual-scroller'; export default { components: { RecycleScroller }, data() { return { list: [...] }; // 长列表数据 } }; </script> <style> .scroller { height: 400px; } .item { height: 50px; } </style> -
vue-virtual-scroll-grid
适用于网格布局,用法类似,但支持横向和纵向滚动。
手动实现虚拟滚动
若需自定义逻辑,可通过计算可见区域索引实现:
<template>
<div class="viewport" @scroll="handleScroll" ref="viewport">
<div class="scroll-placeholder" :style="{ height: totalHeight + 'px' }">
<div
v-for="item in visibleItems"
:key="item.id"
class="item"
:style="{ transform: `translateY(${item.offset}px)` }"
>
{{ item.content }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
allItems: [...], // 完整列表
itemHeight: 50,
startIndex: 0,
endIndex: 0,
viewportHeight: 0
};
},
computed: {
totalHeight() {
return this.allItems.length * this.itemHeight;
},
visibleItems() {
return this.allItems.slice(this.startIndex, this.endIndex).map((item, i) => ({
...item,
offset: (this.startIndex + i) * this.itemHeight
}));
}
},
mounted() {
this.viewportHeight = this.$refs.viewport.clientHeight;
this.calculateRange();
},
methods: {
handleScroll() {
this.calculateRange();
},
calculateRange() {
const scrollTop = this.$refs.viewport.scrollTop;
this.startIndex = Math.floor(scrollTop / this.itemHeight);
this.endIndex = Math.min(
this.startIndex + Math.ceil(this.viewportHeight / this.itemHeight) + 2,
this.allItems.length
);
}
}
};
</script>
<style>
.viewport {
height: 400px;
overflow-y: auto;
position: relative;
}
.scroll-placeholder {
position: relative;
}
.item {
position: absolute;
width: 100%;
height: 50px;
}
</style>
关键优化点
- 动态高度支持
若列表项高度不固定,需使用动态测量(如 IntersectionObserver)或预计算高度。 - 滚动节流
使用requestAnimationFrame或 Lodash 的throttle减少滚动事件频率。 - SSR 兼容
虚拟滚动通常依赖客户端 DOM 操作,需在 SSR 场景下降级处理。
性能对比
- 原生列表:渲染 10,000 项时,DOM 节点数 10,000+,内存占用高。
- 虚拟列表:仅渲染 20-30 项(视窗口大小),DOM 节点数减少 99%+。
根据项目需求选择合适方案,复杂场景推荐使用成熟库。







