vue实现滚动加载
实现滚动加载的基本思路
滚动加载的核心逻辑是监听滚动事件,当用户滚动到接近页面底部时触发数据加载。Vue中可以通过结合v-infinite-scroll指令或手动监听滚动事件实现。
使用v-infinite-scroll指令(Element UI)
如果项目中使用Element UI,可以直接使用其内置的v-infinite-scroll指令:
<template>
<div v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="50">
<div v-for="item in list" :key="item.id">{{ item.content }}</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
busy: false,
page: 1
}
},
methods: {
loadMore() {
this.busy = true
// 模拟API请求
setTimeout(() => {
const newItems = Array(10).fill().map((_, i) => ({
id: this.page * 10 + i,
content: `Item ${this.page * 10 + i}`
}))
this.list.push(...newItems)
this.page++
this.busy = false
}, 1000)
}
}
}
</script>
手动实现滚动监听
对于不使用Element UI的项目,可以手动实现滚动监听:
<template>
<div class="scroll-container" @scroll="handleScroll">
<div v-for="item in list" :key="item.id">{{ item.content }}</div>
<div v-if="loading" class="loading">Loading...</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
loading: false,
page: 1,
hasMore: true
}
},
mounted() {
this.loadData()
},
methods: {
handleScroll(e) {
const { scrollTop, clientHeight, scrollHeight } = e.target
const bottom = scrollHeight - scrollTop - clientHeight < 50
if (bottom && !this.loading && this.hasMore) {
this.loadData()
}
},
loadData() {
this.loading = true
// 模拟API请求
setTimeout(() => {
const newItems = Array(10).fill().map((_, i) => ({
id: this.page * 10 + i,
content: `Item ${this.page * 10 + i}`
}))
this.list = [...this.list, ...newItems]
this.page++
this.loading = false
// 模拟数据加载完毕
if (this.page > 5) this.hasMore = false
}, 1000)
}
}
}
</script>
<style>
.scroll-container {
height: 500px;
overflow-y: auto;
}
.loading {
text-align: center;
padding: 10px;
}
</style>
使用Intersection Observer API
现代浏览器支持Intersection Observer API,性能优于传统滚动事件监听:
<template>
<div class="scroll-container">
<div v-for="item in list" :key="item.id">{{ item.content }}</div>
<div ref="loader" class="loader"></div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
page: 1,
observer: null
}
},
mounted() {
this.initObserver()
this.loadData()
},
beforeDestroy() {
if (this.observer) {
this.observer.disconnect()
}
},
methods: {
initObserver() {
this.observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
this.loadData()
}
})
this.observer.observe(this.$refs.loader)
},
loadData() {
// 模拟API请求
setTimeout(() => {
const newItems = Array(10).fill().map((_, i) => ({
id: this.page * 10 + i,
content: `Item ${this.page * 10 + i}`
}))
this.list = [...this.list, ...newItems]
this.page++
}, 1000)
}
}
}
</script>
<style>
.scroll-container {
height: 500px;
overflow-y: auto;
}
.loader {
height: 20px;
}
</style>
性能优化建议
- 添加防抖处理避免频繁触发加载
- 在组件销毁时移除事件监听
- 显示加载状态和没有更多数据的提示
- 对于大量数据考虑虚拟滚动方案
- 移动端注意滚动性能问题
// 防抖示例
import { debounce } from 'lodash'
methods: {
handleScroll: debounce(function(e) {
// 滚动处理逻辑
}, 200)
}






