vue虚拟滚动实现
vue虚拟滚动实现
虚拟滚动(Virtual Scrolling)是一种优化长列表渲染性能的技术,通过仅渲染可见区域内的元素来减少DOM节点数量。以下是Vue中实现虚拟滚动的几种方法:
使用第三方库
推荐使用成熟的虚拟滚动库,如vue-virtual-scroller或vue-virtual-scroll-list,它们提供了开箱即用的解决方案。
安装vue-virtual-scroller:
npm install vue-virtual-scroller
基本用法:
<template>
<RecycleScroller
class="scroller"
:items="items"
:item-size="50"
key-field="id"
v-slot="{ item }"
>
<div>{{ item.name }}</div>
</RecycleScroller>
</template>
<script>
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
export default {
components: { RecycleScroller },
data() {
return {
items: Array(1000).fill().map((_, i) => ({ id: i, name: `Item ${i}` }))
}
}
}
</script>
<style>
.scroller {
height: 300px;
}
</style>
自定义实现
如果需要手动实现虚拟滚动,可以结合计算属性和滚动事件处理:
<template>
<div class="viewport" @scroll="handleScroll" ref="viewport">
<div class="scroll-content" :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 {
items: Array(10000).fill().map((_, i) => ({
id: i,
content: `Item ${i}`,
height: 50
})),
scrollTop: 0,
viewportHeight: 300
}
},
computed: {
totalHeight() {
return this.items.reduce((sum, item) => sum + item.height, 0)
},
visibleItems() {
let startIndex = 0
let endIndex = 0
let accumulatedHeight = 0
while (startIndex < this.items.length &&
accumulatedHeight + this.items[startIndex].height <= this.scrollTop) {
accumulatedHeight += this.items[startIndex].height
startIndex++
}
endIndex = startIndex
while (endIndex < this.items.length &&
accumulatedHeight < this.scrollTop + this.viewportHeight) {
accumulatedHeight += this.items[endIndex].height
endIndex++
}
return this.items
.slice(startIndex, endIndex)
.map((item, index) => ({
...item,
offset: this.items.slice(0, startIndex + index)
.reduce((sum, i) => sum + i.height, 0)
}))
}
},
mounted() {
this.viewportHeight = this.$refs.viewport.clientHeight
},
methods: {
handleScroll(e) {
this.scrollTop = e.target.scrollTop
}
}
}
</script>
<style>
.viewport {
height: 300px;
overflow-y: auto;
position: relative;
}
.scroll-content {
position: relative;
}
.item {
position: absolute;
width: 100%;
box-sizing: border-box;
}
</style>
性能优化要点
- 使用
transform代替top定位,避免触发重排 - 添加缓冲区,提前渲染可视区域外的部分项目
- 对动态高度的项目实现尺寸测量和缓存
- 使用
requestAnimationFrame节流滚动事件 - 避免在滚动过程中进行复杂的计算
动态高度处理
对于高度不固定的项目,需要先测量并缓存高度:

measureItems() {
this.items.forEach(item => {
const tempDiv = document.createElement('div')
tempDiv.style.position = 'absolute'
tempDiv.style.visibility = 'hidden'
tempDiv.innerText = item.content
document.body.appendChild(tempDiv)
item.height = tempDiv.offsetHeight
document.body.removeChild(tempDiv)
})
}
虚拟滚动能显著提升包含大量数据的列表性能,但实现时需要考虑各种边界情况和性能优化点。对于大多数应用场景,建议优先使用成熟的第三方库。






