vue原生实现无限滚动
vue实现无限滚动的原生方案
在Vue中实现无限滚动可以通过监听滚动事件和计算元素位置来实现,以下是几种常见方法:
监听滚动事件实现
<template>
<div class="scroll-container" @scroll="handleScroll">
<div v-for="item in visibleItems" :key="item.id">
{{ item.content }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
allItems: [], // 所有数据
visibleItems: [], // 当前显示的数据
pageSize: 10,
currentPage: 1
}
},
methods: {
handleScroll(event) {
const container = event.target
const scrollBottom = container.scrollHeight - container.scrollTop - container.clientHeight
if (scrollBottom < 50) {
this.loadMore()
}
},
loadMore() {
const start = (this.currentPage - 1) * this.pageSize
const end = start + this.pageSize
const newItems = this.allItems.slice(start, end)
if (newItems.length) {
this.visibleItems = [...this.visibleItems, ...newItems]
this.currentPage++
}
}
},
mounted() {
// 初始化数据
this.loadMore()
}
}
</script>
<style>
.scroll-container {
height: 500px;
overflow-y: auto;
}
</style>
使用Intersection Observer API
更现代的解决方案是使用Intersection Observer API,性能更好:
<template>
<div class="scroll-container">
<div v-for="item in visibleItems" :key="item.id">
{{ item.content }}
</div>
<div ref="loader" class="loader"></div>
</div>
</template>
<script>
export default {
data() {
return {
allItems: [],
visibleItems: [],
pageSize: 10,
currentPage: 1,
observer: null
}
},
methods: {
loadMore() {
const start = (this.currentPage - 1) * this.pageSize
const end = start + this.pageSize
const newItems = this.allItems.slice(start, end)
if (newItems.length) {
this.visibleItems = [...this.visibleItems, ...newItems]
this.currentPage++
}
}
},
mounted() {
this.observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
this.loadMore()
}
})
this.observer.observe(this.$refs.loader)
this.loadMore()
},
beforeDestroy() {
this.observer.disconnect()
}
}
</script>
<style>
.scroll-container {
height: 500px;
overflow-y: auto;
}
.loader {
height: 20px;
}
</style>
性能优化建议
- 使用虚拟滚动技术处理大量数据
- 添加防抖函数避免频繁触发滚动事件
- 实现数据缓存减少重复请求
- 添加加载状态提示提升用户体验
虚拟滚动实现思路
对于超长列表,可以考虑虚拟滚动方案:
<template>
<div class="virtual-scroll" @scroll="handleScroll" ref="container">
<div class="scroll-content" :style="{ height: totalHeight + 'px' }">
<div
v-for="item in visibleItems"
:key="item.id"
:style="{ transform: `translateY(${item.offset}px)` }"
class="item"
>
{{ item.content }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
allItems: [],
visibleItems: [],
itemHeight: 50,
visibleCount: 0,
startIndex: 0
}
},
computed: {
totalHeight() {
return this.allItems.length * this.itemHeight
}
},
methods: {
handleScroll() {
const scrollTop = this.$refs.container.scrollTop
this.startIndex = Math.floor(scrollTop / this.itemHeight)
this.updateVisibleItems()
},
updateVisibleItems() {
const endIndex = Math.min(
this.startIndex + this.visibleCount,
this.allItems.length - 1
)
this.visibleItems = this.allItems
.slice(this.startIndex, endIndex)
.map((item, index) => ({
...item,
offset: (this.startIndex + index) * this.itemHeight
}))
}
},
mounted() {
this.visibleCount = Math.ceil(
this.$refs.container.clientHeight / this.itemHeight
)
this.updateVisibleItems()
}
}
</script>
<style>
.virtual-scroll {
height: 500px;
overflow-y: auto;
position: relative;
}
.scroll-content {
position: relative;
}
.item {
position: absolute;
height: 50px;
width: 100%;
}
</style>
以上方案可以根据实际需求选择使用,纯滚动事件实现简单但性能稍差,Intersection Observer更现代化,虚拟滚动适合超大数据量场景。







