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

滚动触底加载更多

相关推荐
提笔了无痕12 小时前
Web中Token验证如何实现(go语言)
前端·go·json·restful
戌中横12 小时前
JavaScript——Web APIs DOM
前端·javascript·html
Beginner x_u12 小时前
如何解释JavaScript 中 this 的值?
开发语言·前端·javascript·this 指针
HWL567912 小时前
获取网页首屏加载时间
前端·javascript·vue.js
烟锁池塘柳013 小时前
【已解决】Google Chrome 浏览器报错 STATUS_ACCESS_VIOLATION 的解决方案
前端·chrome
速易达网络13 小时前
基于RuoYi-Vue 框架美妆系统
前端·javascript·vue.js
LYS_061813 小时前
RM赛事C型板九轴IMU解算(4)(卡尔曼滤波)
c语言·开发语言·前端·卡尔曼滤波
We་ct14 小时前
LeetCode 151. 反转字符串中的单词:两种解法深度剖析
前端·算法·leetcode·typescript
yinmaisoft14 小时前
JNPF 表单模板实操:高效复用表单设计指南
前端·javascript·html
37方寸15 小时前
前端基础知识(JavaScript)
开发语言·前端·javascript