代碼可直接複製使用,主要用於頁面容器內的滾動觸底加載
主要參數:
● element 滾動容器dom
● loading 是否加載中
● hasMore 是否有更多,根據分頁總數跟total判斷
● pageInfo 分頁參數信息{ pageNo: number, pageSize: number, total: number }
● loadMore 加載列表的函數,比如getList,該函數是一個async的Promise函數
● threshold 滾頂條距離底部多少px觸發到底事件
/**
* 容器級別的觸底加載更多
* @param {Ref<HTMLElement>} element 滾動容器dom
* @param {Ref<boolean>} loading 加載中
* @param {Ref<boolean>} hasMore 是否有更多
* @param {Ref<{ pageNo: number, pageSize: number, total: number }>} pageInfo 分頁信息
* @param {() => Promise<void>} loadMore 查詢分頁函數
* @param {number} threshold 閾值
*/
export function containeScroll(
element: Ref<HTMLElement>,
loading: Ref<boolean>,
hasMore: Ref<boolean>,
pageInfo: Ref<{ pageNo: number, pageSize: number, total: number }>,
loadMore: () => Promise<void>,
threshold: number = 10) {
// 加載中 或 沒有更多
if (loading.value || !hasMore.value) return;
// 判斷滾動容器是否存在
if (!element.value) return;
const container = element.value;
// 滾動容器高度 + 滾動距離 >= 內容總高度 - 10px(緩衝值)
const isBottom = container.clientHeight + container.scrollTop >= container.scrollHeight - threshold;
if (isBottom && !loading.value && hasMore.value) {
pageInfo.value.pageNo++;
loadMore(); // 到底了,調用加載函數
}
}
頁面結構
<div ref="scrollContainer" @scroll="handleScroll">
<div class="body"></div>
</div>
<script setup lang='ts'>
import { containeScroll } from '@/hook/useInfiniteScroll'
// 加載中
const loading = ref(false)
// 是否有下一頁
const hasMore = ref(true)
// 分頁參數
const pageInfo = ref({
pageNo: 1,
pageSize: 10,
total: 0,
})
// 列表數據
const list = ref([])
async function getList() {
try {
let params = {
pageNo: pageInfo.value.pageNo,
pageSize: pageInfo.value.pageSize
}
loading.value = true
let res = await getListAPI(params)
list.value.push(...res.list)
pageInfo.value.total = res.total
if (pageInfo.value.pageNo * pageInfo.value.pageSize >= pageInfo.value.total) {
hasMore.value = false
}
else {
hasMore.value = true
}
}
finally {
loading.value = false
}
}
// 初始化查詢
getList();
// 滾動容器 dom
const scrollContainer = ref<HTMLDivElement | null>(null)
// 防抖函數,節省性能
const onScroll = debounce(containeScroll, 300)
// 每次滾動時觸發
function handleScroll() {
onScroll(scrollContainer, loading, hasMore, pageInfo, getList)
}
</script>
輔助函數
// 防抖函數
function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): ((...args: Parameters<T>) => void) {
let timer: NodeJS.Timeout | null = null
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
if (timer)
clearTimeout(timer)
timer = setTimeout(() => {
// 使用 apply 綁定 this 上下文
fn.apply(this, args)
timer = null
}, delay)
}
}