簡介
無限滾動是現(xiàn)代網(wǎng)頁應(yīng)用中常見的交互模式,用戶在滾動到頁面底部時自動加載更多內(nèi)容。今天我們將使用 Vue 3 的組合式 API 來實現(xiàn)一個可復用的無限滾動組件。
核心功能
- 監(jiān)聽滾動事件
- 判斷是否滾動到底部
- 觸發(fā)加載更多數(shù)據(jù)
- 支持加載狀態(tài)顯示
- 支持錯誤處理
代碼實現(xiàn)
1. 組件結(jié)構(gòu)
首先創(chuàng)建一個 InfiniteScroll.vue
文件:
<template>
<div class="infinite-scroll-container" ref="containerRef">
<slot></slot>
<div class="loading-status">
<div v-if="loading" class="loading">加載中...</div>
<div v-if="error" class="error">{{ error }}</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
distance: {
type: Number,
default: 100
}
})
const emit = defineEmits(['load-more'])
const containerRef = ref(null)
const loading = ref(false)
const error = ref(null)
// 檢查是否滾動到底部
const isBottom = () => {
const container = containerRef.value
return container.scrollHeight - container.scrollTop - container.clientHeight < props.distance
}
// 處理滾動事件
const handleScroll = async () => {
if (loading.value || error.value) return
if (isBottom()) {
try {
loading.value = true
await emit('load-more')
loading.value = false
error.value = null
} catch (err) {
error.value = err.message
loading.value = false
}
}
}
onMounted(() => {
containerRef.value.addEventListener('scroll', handleScroll)
})
onUnmounted(() => {
containerRef.value.removeEventListener('scroll', handleScroll)
})
</script>
<style scoped>
.infinite-scroll-container {
height: 100%;
overflow-y: auto;
}
.loading-status {
padding: 1rem;
text-align: center;
}
.loading {
color: #666;
}
.error {
color: #ff4444;
}
</style>
2. 使用示例
<template>
<div class="app">
<infinite-scroll @load-more="loadMore">
<div v-for="item in items" :key="item.id" class="item">
{{ item.content }}
</div>
</infinite-scroll>
</div>
</template>
<script setup>
import { ref } from 'vue'
import InfiniteScroll from './components/InfiniteScroll.vue'
const items = ref([])
const page = ref(1)
const loadMore = async () => {
// 模擬 API 請求
const newItems = await fetchData(page.value)
items.value.push(...newItems)
page.value++
}
// 模擬數(shù)據(jù)獲取
const fetchData = (page) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Array.from({ length: 10 }, (_, i) => ({
id: page * 10 + i,
content: `Item ${page * 10 + i}`
})))
}, 1000)
})
}
</script>
<style>
.app {
height: 100vh;
}
.item {
padding: 20px;
border-bottom: 1px solid #eee;
}
</style>
關(guān)鍵實現(xiàn)細節(jié)
1. 滾動檢測
使用 scrollHeight
、scrollTop
和 clientHeight
來判斷是否滾動到底部:
-
scrollHeight
: 內(nèi)容總高度 -
scrollTop
: 已滾動距離 -
clientHeight
: 可視區(qū)域高度
2. 防抖處理
在實際應(yīng)用中淫茵,建議對 handleScroll
函數(shù)進行防抖處理,避免頻繁觸發(fā):
import { debounce } from 'lodash'
const handleScroll = debounce(async () => {
// 滾動處理邏輯
}, 200)
3. 錯誤處理
組件內(nèi)置了簡單的錯誤處理機制蹬跃,當加載失敗時會顯示錯誤信息匙瘪,并暫停后續(xù)加載。
組件特點
- 使用 Vue 3 組合式 API蝶缀,代碼更清晰
- 支持自定義觸發(fā)距離
- 內(nèi)置加載狀態(tài)和錯誤處理
- 可通過插槽自定義內(nèi)容
使用注意事項
- 確保父容器設(shè)置了固定高度
- 合理設(shè)置觸發(fā)距離(distance)
- 處理好數(shù)據(jù)加載的異常情況
- 考慮是否需要添加數(shù)據(jù)加載完成的判斷
總結(jié)
這個無限滾動組件封裝了常用的滾動加載功能丹喻,可以方便地集成到各種列表場景中。通過 Vue 3 的組合式 API翁都,我們能夠更清晰地組織代碼邏輯碍论,提供更好的可維護性。