vue3中使用element-plus的el-scrollbar实现滚动触底加载更多
1.实现步骤:
a. 数据结构与分页参数设计
b. 滚动事件监听与防抖处理
c. 触底判断逻辑(滚动高度 + 可视高度 >= 页面总高度 - 预加载阈值 )
d. 加载更多数据请求
e. 加载状态与无数据提示
1.1 数据结构和状态管理
首先,我们需要定义分页相关的数据结构:
cpp
// 分页参数状态
const pageParams = reactive({
paifeng: {
pageIndex: 1, // 当前页码
pageSize: 4, // 每页数据量
total: 0, // 总数据量
loaded: false // 是否已加载完所有数据
},
})
// 可见数据存储
const paifengVisibleData = ref([])
// 加载状态控制
const loadingMore = reactive({
paifeng: false,
})
1.2 滚动容器设置
使用 el-scrollbar 组件创建可滚动的容器:
cpp
<template>
<el-scrollbar
@scroll="handleScrollPaifeng"
ref="paifengScrollbar"
height="100%"
class="scrollbar-custom"
>
<!-- 数据列表 -->
<div v-for="(device, index) in paifengVisibleData" :key="index">
<!-- 设备数据展示 -->
</div>
<!-- 加载提示 -->
<div v-if="loadingMore.paifeng && !pageParams.paifeng.loaded">
正在加载更多...
</div>
<!-- 无更多数据提示 -->
<div v-if="pageParams.paifeng.loaded && paifengVisibleData.length > 0">
已显示全部数据
</div>
</el-scrollbar>
</template>
<style scoped>
// 计算模块高度:4个模块 * 每个模块高度 + 4个间距 * 间距大小(16px)
.scrollbar-custom {
max-height: calc(14.5rem * 4 + 1rem * 4);
}
</style>
1.3 滚动事件处理核心逻辑
实现滚动触底检测的关键是监听滚动事件,计算是否滚动到底部:
cpp
// 滚动容器引用
const paifengScrollbar = ref<any>(null)
// 防抖相关变量
let scrollDebounceTimerPaifeng: NodeJS.Timeout | null = null
let lastScrollTime = 0
// 滚动处理函数
const handleScrollPaifeng = () => {
// 防抖处理:避免频繁触发
const now = Date.now()
if (now - lastScrollTime < 200) {
return // 200ms内不重复处理
}
lastScrollTime = now
// 清除之前的定时器
if (scrollDebounceTimerPaifeng) {
clearTimeout(scrollDebounceTimerPaifeng)
}
// 设置新的定时器(150ms防抖延迟)
scrollDebounceTimerPaifeng = setTimeout(() => {
// 通过 wrapRef 获取滚动容器
const wrap = paifengScrollbar.value?.wrapRef
if (!wrap) return
// 获取滚动容器的关键信息
const scrollTop = wrap.scrollTop // 当前滚动高度
const scrollHeight = wrap.scrollHeight // 内容总高度
const clientHeight = wrap.clientHeight // 容器可见高度
// 计算距离底部的距离
const distanceToBottom = scrollHeight - scrollTop - clientHeight
// 判断是否应该加载更多(距离底部100px以内触发)
const shouldLoad = distanceToBottom < 100
// 检查加载条件
if (shouldLoad &&
!pageParams.paifeng.loaded &&
!loadingMore.paifeng) {
console.log('滚动到底部,开始加载更多数据...')
loadingMore.paifeng = true
loadMorePaifeng()
}
}, 150)// 防抖延迟
}
标准触底检测公式:滚动高度 + 可视高度 >= 页面总高度 - 预加载阈值
cpp
// 标准触底检测公式
const isBottom = scrollTop + clientHeight >= scrollHeight - threshold
scrollTop:滚动条到盒子顶部高度
clientHeight:可视区域高度
scrollHeight:页面总高度
threshold:触发加载的阈值
cpp
// 或者使用距离计算(更直观)
const distanceToBottom = scrollHeight - scrollTop - clientHeight
const isBottom = distanceToBottom <= threshold
1.4 数据加载函数
cpp
// 加载更多数据
const loadMorePaifeng = async () => {
try {
// 递增页码
pageParams.paifeng.pageIndex += 1
// 调用API获取数据
await getPaifengList()
} catch (error) {
console.error('加载更多排风数据失败:', error)
// 如果失败,回退页码
pageParams.paifeng.pageIndex -= 1
loadingMore.paifeng = false
}
}
// API请求配置
const { execute: getPaifengList } = useRequest(api_paifeng_list(queryParamsList, pageParams.paifeng), {
onSuccess(res) {
if (res && Array.isArray(res)) {
// 第一页直接设置,后续页码追加数据
if (pageParams.paifeng.pageIndex === 1) {
paifengVisibleData.value = res
} else {
paifengVisibleData.value = [...paifengVisibleData.value, ...res]
}
// 更新总条数
pageParams.paifeng.total = paifengVisibleData.value.length
// 判断是否已加载完所有数据
// 如果返回的数据条数小于pageSize,说明没有更多了
const hasMoreData = res.length >= pageParams.paifeng.pageSize
pageParams.paifeng.loaded = !hasMoreData
} else {
// 如果没有数据,标记为已加载完
pageParams.paifeng.loaded = true
}
// 重置加载状态
loadingMore.paifeng = false
},
onError(error) {
console.error('获取排风数据失败:', error)
loadingMore.paifeng = false
// 如果加载失败,回退页码
if (pageParams.paifeng.pageIndex > 1) {
pageParams.paifeng.pageIndex--
}
}
})
1.5 初始化和清理
cpp
// 初始化加载第一页数据
onMounted(() => {
if (pageParams.paifeng.pageIndex === 1) {
getPaifengList()
}
})
// 组件卸载时清理定时器
onUnmounted(() => {
if (scrollDebounceTimerPaifeng) clearTimeout(scrollDebounceTimerPaifeng)
})
2.实现效果
滚动触底加载更多