vue虚拟滚动列表实现
虚拟滚动列表的实现原理
虚拟滚动(Virtual Scrolling)通过仅渲染可视区域内的元素来优化长列表性能。核心思想是根据滚动位置动态计算可见项,减少DOM节点数量。
基于vue-virtual-scroll-list的实现
安装依赖库:
npm install vue-virtual-scroll-list --save
基础用法示例:
<template>
<virtual-list
:size="50"
:remain="8"
:items="items"
>
<template v-slot="{ item }">
<div class="item">{{ item.content }}</div>
</template>
</virtual-list>
</template>
<script>
import VirtualList from 'vue-virtual-scroll-list'
export default {
components: { VirtualList },
data() {
return {
items: Array(10000).fill().map((_, i) => ({
id: i,
content: `Item ${i}`
}))
}
}
}
</script>
<style>
.item {
height: 50px;
line-height: 50px;
border-bottom: 1px solid #eee;
}
</style>
自定义实现方案
手动实现的基本逻辑:

<template>
<div
class="viewport"
@scroll="handleScroll"
ref="viewport"
>
<div
class="scroll-space"
:style="{ height: totalHeight + 'px' }"
>
<div
class="visible-items"
:style="{ transform: `translateY(${offset}px)` }"
>
<div
v-for="item in visibleItems"
:key="item.id"
class="item"
:style="{ height: itemHeight + 'px' }"
>
{{ item.content }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
items: Array,
itemHeight: {
type: Number,
default: 50
},
visibleCount: {
type: Number,
default: 10
}
},
data() {
return {
startIndex: 0,
offset: 0
}
},
computed: {
totalHeight() {
return this.items.length * this.itemHeight
},
endIndex() {
return Math.min(
this.startIndex + this.visibleCount,
this.items.length
)
},
visibleItems() {
return this.items.slice(
this.startIndex,
this.endIndex
)
}
},
methods: {
handleScroll() {
const scrollTop = this.$refs.viewport.scrollTop
this.startIndex = Math.floor(scrollTop / this.itemHeight)
this.offset = this.startIndex * this.itemHeight
}
}
}
</script>
<style>
.viewport {
height: 500px;
overflow-y: auto;
position: relative;
}
.scroll-space {
position: relative;
}
.visible-items {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
</style>
性能优化技巧
设置适当的key属性避免不必要的重渲染,使用稳定的唯一标识符而非数组索引
添加滚动节流处理:
import { throttle } from 'lodash'
methods: {
handleScroll: throttle(function() {
// 计算逻辑
}, 16)
}
对于动态高度项目,需要实现尺寸测量和位置缓存。可以使用ResizeObserver API监测元素实际高度并更新位置计算

动态高度处理方案
安装依赖:
npm install vue-virtual-scroller
动态高度示例:
<template>
<RecycleScroller
class="scroller"
:items="items"
:item-size="32"
key-field="id"
v-slot="{ item }"
>
<div class="dynamic-item">
{{ item.text }}
</div>
</RecycleScroller>
</template>
<script>
import { RecycleScroller } from 'vue-virtual-scroller'
export default {
components: { RecycleScroller },
data() {
return {
items: generateDynamicItems()
}
}
}
</script>
<style>
.scroller {
height: 400px;
}
.dynamic-item {
padding: 10px;
}
</style>
注意事项
滚动容器需要明确设置高度,否则无法正确计算可视区域。对于服务端渲染(SSR)场景,需要特殊处理初始渲染
大数据量情况下,建议配合分页加载策略。可通过Intersection Observer API实现滚动到底部自动加载更多数据






