【前端】移动端上拉加载 & 下拉刷新实现方案(原生 JS / Vue / React / jQuery / Angular)

📜移动端上拉加载 & 下拉刷新实现方案(原生 JS / Vue / React / jQuery / Angular)


🎉一、实现原理概述

移动端的 上拉加载下拉刷新 是常见的交互功能,其核心是监听滚动事件或手势滑动事件,并判断用户是否触发了“上拉”或“下拉”的动作。

核心逻辑:

  • 下拉刷新:用户从顶部下拉,触发数据重新加载。
  • 上拉加载:用户滚动到底部附近,触发分页加载更多数据。

🛠️二、通用实现思路(适用于所有技术栈)

✅ 实现步骤(原生 JS 思路):

1. 获取容器元素

参数:

  • container:表示滚动容器元素,可以是整个页面窗口(window)或某个特定的DOM元素。

实现思路:

  • 使用 document.querySelectordocument.getElementById 获取特定的滚动容器。
  • 如果是整个页面,可以直接使用 window
const container = document.querySelector('.scroll-container'); // 或者 window;

2. 监听滚动事件

参数:

  • event:滚动事件对象,包含滚动相关的信息。

实现思路:

  • 使用 addEventListener 监听滚动事件。
  • 如果监听的是 window,直接使用 window.addEventListener('scroll', handler)
  • 如果是自定义容器,监听容器的滚动事件。
container.addEventListener('scroll', handleScroll);

3. 判断是否到达底部(上拉加载)

参数:

  • scrollTop:滚动容器当前滚动的距离。
  • clientHeight:滚动容器的可视高度。
  • scrollHeight:滚动容器内容的总高度。
  • threshold:触发加载的阈值,通常设置为50到100像素。

实现思路:

  • 使用公式 scrollTop + clientHeight >= scrollHeight - threshold 判断是否接近底部。
  • 触发加载更多数据的逻辑。
function handleScroll(event) {
   
   
    const scrollTop = container.scrollTop;
    const clientHeight = container.clientHeight;
    const scrollHeight = container.scrollHeight;
    const threshold = 50;

    if (scrollTop + clientHeight >= scrollHeight - threshold) {
   
   
        loadMoreContent();
    }
}

4. 判断是否下拉(下拉刷新)

参数:

  • startY:触摸开始的Y坐标。
  • currentY:当前触摸的Y坐标。
  • pullDownDistance:下拉的距离,用于判断是否达到刷新条件。

实现思路:

  • 监听 touchstarttouchmove 事件。
  • 记录初始触摸点 startY,在 touchmove 时计算 currentY - startY,判断是否下拉。
let startY = 0;

container.addEventListener('touchstart', (event) => {
   
   
    startY = event.touches[0].clientY;
});

container.addEventListener('touchmove', (event) => {
   
   
    const currentY = event.touches[0].clientY;
    const pullDownDistance = currentY - startY;

    if (pullDownDistance > 50) {
   
    // 假设下拉50像素触发刷新
        refreshContent();
    }
});

5. 防抖与节流控制

参数:

  • delay:防抖或节流的延迟时间,通常设置为200到500毫秒。

实现思路:

  • 使用 setTimeout 实现防抖,确保在滚动停止后延迟执行。
  • 使用 lodash.throttle 或自定义节流函数控制触发频率。
function debounce(func, delay) {
   
   
    let timeoutId;
    return function() {
   
   
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => func.apply(this, arguments), delay);
    };
}

const throttledScrollHandler = debounce(handleScroll, 300);
container.addEventListener('scroll', throttledScrollHandler);

6. 加载状态管理

参数:

  • isLoading:布尔值,表示是否正在加载数据。
  • loadingElement:表示加载动画的DOM元素。

实现思路:

  • 在加载数据时,显示加载动画并设置 isLoadingtrue
  • 数据加载完成后,隐藏加载动画并设置 isLoadingfalse
let isLoading = false;
const loadingElement = document.querySelector('.loading-animation');

function loadMoreContent() {
   
   
    if (isLoading) return;

    isLoading = true;
    loadingElement.style.display = 'block';

    // 模拟异步加载
    setTimeout(() => {
   
   
        // 加载数据
        isLoading = false;
        loadingElement.style.display = 'none';
    }, 1000);
}

7. 数据加载完成后更新视图

参数:

  • newData:新加载的数据。

实现思路:

  • 在数据加载完成后,将新数据追加到现有数据中。
  • 更新DOM以反映新数据。
function updateView(newData) {
   
   
    const contentElement = document.querySelector('.content');
    newData.forEach(item => {
   
   
        const element = document.createElement('div');
        element.textContent = item.title;
        contentElement.appendChild(element);
    });
}

8. 异常处理

参数:

  • retryCount:重试次数。
  • maxRetries:最大重试次数。

实现思路:

  • 在数据加载失败时,显示错误信息。
  • 提供重试按钮或自动重试机制。
function loadMoreContent() {
   
   
    if (isLoading) return;

    isLoading = true;
    loadingElement.style.display = 'block';

    fetchData()
        .then(data => {
   
   
            updateView(data);
            isLoading = false;
            loadingElement.style.display = 'none';
        })
        .catch(error => {
   
   
            console.error('Failed to load data:', error);
            isLoading = false;
            loadingElement.style.display = 'none';
            // 显示错误信息
        });
}

🧩三、原生 JavaScript 实现代码(完整示例)

下面是老曹添加了详细注释的完整代码,解释了每一行代码的功能和作用:

<div id="container" style="height: 100vh; overflow-y: scroll;">
  <div id="refreshIndicator" class="refresh-indicator">下拉刷新</div>
  <ul id="list">
    <!-- 列表项动态插入 -->
  </ul>
  <div id="loading" class="loading">加载中...</div>
</div>

<script>
// 获取DOM元素
const container = document.getElementById('container'); // 滚动容器
const list = document.getElementById('list'); // 列表容器
const refreshIndicator = document.getElementById('refreshIndicator'); // 下拉刷新指示器
const loading = document.getElementById('loading'); // 加载中指示器

// 初始化状态变量
let isRefreshing = false; // 是否正在刷新
let isLoadin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈前端老曹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值