vue 实现长列表
实现长列表的常见方法
在Vue中处理长列表时,直接渲染所有DOM节点会导致性能问题。以下是几种优化方案:
虚拟滚动(Virtual Scrolling)
虚拟滚动通过只渲染可视区域内的元素来提升性能。推荐使用现成库如vue-virtual-scroller:
npm install vue-virtual-scroller
示例代码:
<template>
<RecycleScroller
class="scroller"
:items="list"
:item-size="50"
key-field="id"
v-slot="{ item }"
>
<div class="item">{{ item.text }}</div>
</RecycleScroller>
</template>
<script>
import { RecycleScroller } from 'vue-virtual-scroller'
export default {
components: { RecycleScroller },
data() {
return {
list: Array.from({ length: 10000 }, (_, i) => ({
id: i,
text: `Item ${i}`
}))
}
}
}
</script>
<style>
.scroller {
height: 400px;
}
.item {
height: 50px;
line-height: 50px;
}
</style>
分页加载(Pagination)
对于非实时滚动的场景,分页是更简单的解决方案:
<template>
<div>
<div v-for="item in visibleItems" :key="item.id">
{{ item.text }}
</div>
<button @click="loadMore">加载更多</button>
</div>
</template>
<script>
export default {
data() {
return {
allItems: [],
pageSize: 20,
currentPage: 1
}
},
computed: {
visibleItems() {
return this.allItems.slice(0, this.pageSize * this.currentPage)
}
},
methods: {
loadMore() {
this.currentPage++
}
}
}
</script>
无限滚动(Infinite Scroll)
结合滚动事件动态加载数据:
<template>
<div class="list-container" @scroll="handleScroll">
<div v-for="item in visibleItems" :key="item.id">
{{ item.text }}
</div>
<div v-if="loading" class="loading">加载中...</div>
</div>
</template>
<script>
export default {
data() {
return {
allItems: [],
visibleItems: [],
batchSize: 20,
loading: false
}
},
mounted() {
this.loadItems()
},
methods: {
loadItems() {
this.loading = true
// 模拟异步加载
setTimeout(() => {
const newItems = Array.from({ length: this.batchSize }, (_, i) => ({
id: this.visibleItems.length + i,
text: `Item ${this.visibleItems.length + i}`
}))
this.visibleItems = [...this.visibleItems, ...newItems]
this.loading = false
}, 500)
},
handleScroll(e) {
const { scrollTop, clientHeight, scrollHeight } = e.target
if (scrollHeight - (scrollTop + clientHeight) < 50 && !this.loading) {
this.loadItems()
}
}
}
}
</script>
<style>
.list-container {
height: 500px;
overflow-y: auto;
}
</style>
性能优化建议
- 为列表项使用稳定的
key,避免使用索引 - 避免在列表项中使用复杂的计算属性
- 对于复杂列表项,考虑使用
v-once指令 - 使用
Object.freeze冻结不需要响应式的数据
选择方案的标准
- 数据量小于1000:普通渲染
- 1000-10000:分页或无限滚动
- 超过10000:虚拟滚动
根据具体场景选择最适合的方案,虚拟滚动提供最佳性能但实现复杂度较高,分页和无限滚动更易于实现但用户体验略有不同。







