vue3中使用element-plus的el-scrollbar实现滚动触底加载更多

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.实现效果

滚动触底加载更多

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax