vue虚拟滚动实现
vue虚拟滚动实现
虚拟滚动是一种优化长列表渲染性能的技术,通过仅渲染可视区域内的元素来减少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"
>
<template v-slot="{ item }">
<div class="item">{{ item.name }}</div>
</template>
</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(10000).fill().map((_, i) => ({ id: i, name: `Item ${i}` }))
}
}
}
</script>
<style>
.scroller {
height: 400px;
}
.item {
height: 50px;
padding: 10px;
}
</style>
手动实现虚拟滚动
对于需要自定义实现的情况,可通过以下方式:
<template>
<div class="virtual-list" @scroll="handleScroll" ref="container">
<div class="phantom" :style="{ height: totalHeight + 'px' }">
<div
class="content"
:style="{ transform: `translateY(${startOffset}px)` }"
>
<div
v-for="item in visibleData"
:key="item.id"
class="list-item"
:style="{ height: itemSize + 'px' }"
>
{{ item.value }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
listData: Array,
itemSize: {
type: Number,
default: 50
},
visibleCount: {
type: Number,
default: 10
}
},
data() {
return {
startIndex: 0,
endIndex: this.visibleCount
}
},
computed: {
totalHeight() {
return this.listData.length * this.itemSize
},
visibleData() {
return this.listData.slice(this.startIndex, this.endIndex)
},
startOffset() {
return this.startIndex * this.itemSize
}
},
methods: {
handleScroll() {
const scrollTop = this.$refs.container.scrollTop
this.startIndex = Math.floor(scrollTop / this.itemSize)
this.endIndex = this.startIndex + this.visibleCount
}
}
}
</script>
<style>
.virtual-list {
height: 500px;
overflow-y: auto;
position: relative;
}
.phantom {
position: absolute;
left: 0;
right: 0;
top: 0;
}
.content {
position: absolute;
left: 0;
right: 0;
}
.list-item {
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
padding: 0 16px;
}
</style>
性能优化要点
- 使用
transform代替top进行定位,避免重排 - 合理设置缓冲区,提前加载可视区域外的部分数据
- 对于动态高度项目,需要实现尺寸测量和位置缓存
- 使用
requestAnimationFrame优化滚动事件处理
动态高度处理
对于不定高度的项目,需要先测量并缓存高度:
// 在mounted中测量初始高度
mounted() {
this.cachedHeights = []
this.$nextTick(() => {
const items = this.$el.querySelectorAll('.list-item')
items.forEach((item, index) => {
this.cachedHeights[index] = item.getBoundingClientRect().height
})
this.calculatePositions()
})
},
methods: {
calculatePositions() {
this.positions = this.listData.map((_, index) => {
const prevPosition = this.positions[index - 1] || { top: 0, bottom: 0 }
return {
top: prevPosition.bottom,
bottom: prevPosition.bottom + (this.cachedHeights[index] || this.defaultHeight)
}
})
this.totalHeight = this.positions[this.positions.length - 1].bottom
}
}
以上实现方式可根据具体需求选择,第三方库适合快速实现,手动实现则提供更高灵活性。






