在VUE3实现触底加载功能

要在Vue中实现触底加载,主要可以通过以下几个步骤:1、监听滚动事件2、判断是否触底3、触发加载更多数据的函数。具体实现方法包括在组件中监听滚动事件,判断用户是否滚动到底部,并在触底时执行加载更多数据的函数。

一、监听滚动事件

1. onMounted 钩子函数
onMounted(() => {
  // 步骤 1:获取监控报警列表
  getMonitorAlarmList(true);
  
  // 步骤 2:绑定滚动事件监听
  if (scrollContainer.value) {
    scrollContainer.value.addEventListener('scroll', handleScroll);
  }
});
const scrollContainer = ref(null)
 <div class="right-box" ref="scrollContainer" >
在div引用,滚动条监控就绑定到了这个div表中

 

  • 功能说明
    • 数据初始化getMonitorAlarmList(true) 在组件挂载后立即调用,通常用于异步请求数据并更新页面;
    • 事件绑定:通过模板引用 scrollContainer.value 获取 DOM 元素,并为其添加 scroll 事件监听器,滚动时触发 handleScroll 方法;
  • 关键细节
    • 使用 if (scrollContainer.value) 确保 DOM 元素已渲染完成后再操作,避免空引用错误;
    • 滚动监听常用于实现“滚动加载更多”等动态交互功能。

2. onUnmounted 钩子函数
onUnmounted(() => {
  // 清除滚动事件监听
  if (scrollContainer.value) {
    scrollContainer.value.removeEventListener('scroll', handleScroll);
  }
});
  • 功能说明
    • 资源清理:组件销毁前移除 scroll 事件监听,防止组件卸载后事件回调仍被触发,导致内存泄漏或意外行为;
  • 关键细节
    • 必须通过 removeEventListener 移除与添加时完全相同的函数引用(此处 handleScroll 需保持一致性);
    • 即使组件被 v-if 隐藏或路由切换,也会触发 onUnmounted 进行清理。

二、判断是否触底 

const handleScroll = throttle(() => {
  if (!scrollContainer.value || 
      monitorLoading.value || 
      !hasMoreData.value) return

  const container = scrollContainer.value
  const { scrollTop, scrollHeight, clientHeight } = container
  const scrollBottom = scrollHeight - (scrollTop + clientHeight)
  console.log('--------------------------')
  // 距离底部50px时触发加载
  if (scrollBottom < 50 && scrollBottom > 0) {
    loadPreviousData()
  }
}, 200)

以下是对这段代码的逐行解析,结合滚动事件处理和节流技术实现原理:


一、代码结构概览

这段代码通过 ​**throttle 节流函数** 包装了一个滚动事件处理器 handleScroll,核心目标是实现滚动到底部时加载历史数据的功能。代码逻辑可分为三部分:

  1. 节流控制:限制滚动事件触发频率
  2. 条件校验:过滤无效的滚动事件
  3. 滚动位置计算:判断是否需要加载数据

二、逐行详细解析

1. 节流函数包装
const handleScroll = throttle(() => {
  // ...
}, 200)
  • 技术背景
    使用 throttle 函数将实际处理逻辑包装为每 ​200ms 最多执行一次(根据搜索结果中的时间戳版节流实现)。
  • 作用
    避免高频滚动事件导致 loadPreviousData 被频繁调用,降低性能消耗(如接口重复请求、DOM重复计算等)。
  • 实现细节
    若使用增强版节流实现(如搜索结果的 首尾双触发 版本),能保证最后一次滚动必定触发加载。

2. 前置条件校验
if (!scrollContainer.value || monitorLoading.value || !hasMoreData.value) return
  • 三个校验条件
    • ​**!scrollContainer.value**:确保滚动容器 DOM 已正确挂载(常见于 Vue/React 的模板引用未初始化时)
    • ​**monitorLoading.value**:防止当前数据加载未完成时重复触发请求(类似防重提交锁)
    • ​**!hasMoreData.value**:无更多数据时停止加载(分页场景的终止条件)
  • 设计意义
    通过逻辑短路 (return) 提前过滤 ​75% 以上的无效事件,降低后续计算消耗。

3. 滚动容器参数提取
const container = scrollContainer.value
const { scrollTop, scrollHeight, clientHeight } = container
  • 关键属性
    • ​**scrollTop**:已滚动距离(从顶部开始计算)
    • ​**scrollHeight**:容器总高度(包括不可见区域)
    • ​**clientHeight**:容器可视区域高度
  • 参数关系
    scrollTop + clientHeight 表示当前滚动位置底部在总高度的绝对坐标。

4. 滚动到底部判断
const scrollBottom = scrollHeight - (scrollTop + clientHeight)
if (scrollBottom < 50 && scrollBottom > 0) {
  loadPreviousData()
}
  • 计算逻辑
    scrollBottom 表示距离容器底部的剩余未滚动距离,​**<50px** 时触发加载(常见加载阈值设定)。
  • 双重条件
    • ​**scrollBottom < 50**:距离底部小于 50 像素时触发
    • ​**scrollBottom > 0**:避免容器高度不足时误判(如内容未撑满容器)
  • 业务扩展
    可调整阈值(如 100px)平衡用户体验与性能,或添加加载动画提示。

5. 调试输出(可选)
console.log('--------------------------')
  • 作用
    输出分隔线便于控制台观察事件触发频次,实际生产环境需移除。
  • 调试技巧
    可改为记录滚动位置:console.log('ScrollBottom:', scrollBottom)

三、综合技术要点

  1. 节流实现选择

          若需精确控制首次/末次触发,建议采用增强版节流
    • 时间间隔(200ms)需根据接口响应速度调整,避免加载速度跟不上滚动触发频率
  2. 滚动容器类型

    • 适用于 overflow: auto/scroll 的定高容器
    • 若为窗口滚动,需改用 window.addEventListener 并计算 document.documentElement 相关属性
  3. 性能优化

    • 使用 IntersectionObserver API 可替代手动计算(更高效但兼容性需考虑)
    • 加载数据时禁用节流:monitorLoading.value = true 期间节流函数自动跳过逻辑

三、触发加载更多数据的函数

const loadPreviousData = () => {
  const currentStart = moment(queryParamsTime.value[0])
  const newEnd = currentStart.clone()
  const newStart = currentStart.clone().subtract(5, 'minutes')

  // 时间范围有效性验证
  if (moment().diff(newStart, 'days') > 30) {
    hasMoreData.value = false
    return
  }
  // 保持显示范围为扩展后的时间(不修改结束时间)
  displayTimeRange.value = [newStart.format('YYYY-MM-DD HH:mm'), displayTimeRange.value[1]]
  queryParamsTime.value = [
    newStart.format('YYYY-MM-DD HH:mm'),
    newEnd.format('YYYY-MM-DD HH:mm')
  ]

  getMonitorAlarmList(false)
}

一、函数功能概述

此函数用于在用户滚动加载历史数据时,​动态扩展查询时间范围并触发数据请求,核心逻辑如下:

  1. 时间范围计算:每次向前扩展 5 分钟的时间窗口;
  2. 有效性校验:限制最多查询 30 天内的数据;
  3. 状态更新:同步更新界面显示时间和实际查询参数;
  4. 数据加载:调用 API 获取指定时间段的监控报警数据。

二、逐行代码解析

1. 时间范围初始化
const currentStart = moment(queryParamsTime.value[0]); // 当前查询的起始时间
const newEnd = currentStart.clone();                  // 新时间段的结束时间(保持原起始时间不变)
const newStart = currentStart.clone().subtract(5, 'minutes'); // 新起始时间 = 当前起始时间 -5 分钟
  • 逻辑说明
    • queryParamsTime.value[0] 是上一次请求的时间起点(如 "2023-10-01 10:00");
    • newEnd 保持与当前起始时间一致,形成 ​左闭右开 区间 [newStart, newEnd)
    • subtract(5, 'minutes') 将每次查询的时间窗口向前推移 5 分钟(类似分页查询的 offset)。
    • queryParamsTime.value[0]:获取一个数组中的第一个元素,该数组可能存储了时间相关的数据。
    • moment(...):将获取的时间值转换为 moment 对象,便于后续的时间操作(如格式化、计算等)。

2. 时间有效性校验
if (moment().diff(newStart, 'days') > 30) { 
  hasMoreData.value = false; // 标记无更多数据
  return; 
}
  • 校验逻辑

    • moment().diff(newStart, 'days') 计算当前时间与 newStart 的间隔天数;
    • 若 newStart 早于 30 天前,则禁止继续加载(假设系统仅保留 30 天内的数据);
    • hasMoreData.value 用于控制 UI 显示(如隐藏“加载更多”按钮)。
  • 潜在问题

    • 时区敏感性:若 moment() 未显式指定时区,可能导致跨时区系统计算错误;
    • 边界条件diff 返回浮点数(如 30.1 天),建议改为 >= 30 更严格。

3. 更新显示时间范围
displayTimeRange.value = [
  newStart.format('YYYY-MM-DD HH:mm'), // 新起始时间
  displayTimeRange.value[1]            // 保持原结束时间不变
];
  • 作用
    • 扩展界面显示的时间范围(例如从 10:00-10:05 变为 09:55-10:05);
    • 用户可直观看到加载了更早时间段的数据。

4. 更新查询参数
queryParamsTime.value = [
  newStart.format('YYYY-MM-DD HH:mm'), // 新起始时间
  newEnd.format('YYYY-MM-DD HH:mm')    // 新结束时间(原起始时间)
];
  • 设计意图
    • 确保下一次数据请求使用新的时间窗口;
    • 后端接口可能根据 start 和 end 参数筛选数据。

5. 触发数据加载
getMonitorAlarmList(false); // 参数 false 表示“加载更多”而非首次加载
  • 参数设计
    • false 可能用于区分初始化加载和增量加载(例如不显示加载动画);
    • 需确保 getMonitorAlarmList 内部使用最新的 queryParamsTime.value

三、潜在优化点

1. 时间计算精度
  • 问题:硬编码 5 分钟 可能导致最后一页数据遗漏(如数据按 10 分钟分段);
  • 建议:根据实际数据颗粒度动态调整步长,或由接口返回下次查询的起始时间。
2. 时区处理
// 显式指定 UTC 时间
const currentStart = moment.utc(queryParamsTime.value[0]);
  • 避免服务器与客户端时区不一致导致时间窗口错位。
3. 状态管理
  • 问题:直接修改 hasMoreData.value 可能未考虑接口返回的实际数据量;
  • 建议:根据接口响应判断是否还有更多数据(如返回 isLastPage 标志)。
4. 防御性编程
// 确保时间字符串有效
if (!moment(queryParamsTime.value[0]).isValid()) return;

四、总结

此函数通过时间窗口滑动实现了按需加载历史数据,核心逻辑清晰但需注意:

  1. 时间计算的准确性与时区处理;
  2. 状态同步​(显示时间 vs 查询参数);
  3. 扩展性​(步长调整、数据分段逻辑)。
    结合前文滚动事件处理,形成完整的分页加载交互闭环。

 定义一个时间选择器

    <el-form :model="queryParams" :inline="true" label-width="80px">
      <el-form-item label="">
        <el-date-picker v-model="displayTimeRange" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间"
          style="width:400px;" format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm" @change="handleTimeChange" />
      </el-form-item>
    </el-form>

每五分钟有一个时间间隔

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值