Skip to content

移动端如何实现下拉滚动加载

移动端实现下拉滚动加载(也叫“上拉加载更多”或“无限滚动”)通常用于列表页,如商品列表、评论等,当用户滚动到页面底部时自动加载下一页数据。下面是常见的实现方式和注意事项:

✅ 一、基本实现原理

1. 监听滚动事件

在滚动区域内监听 scroll 事件,当滚动到底部时触发加载逻辑。

html
<div id="scroll-container" style="height: 500px; overflow-y: auto;">
  <ul id="list"></ul>
  <div id="loading">加载中...</div>
</div>
js
const container = document.getElementById('scroll-container');
container.addEventListener('scroll', () => {
  const { scrollTop, scrollHeight, clientHeight } = container;

  if (scrollTop + clientHeight >= scrollHeight - 10) {
    // 距底部10px时触发加载
    loadMore();
  }
});

function loadMore() {
  // 加载下一页数据
}

✅ 二、常见优化点

1. 节流/防抖

避免 scroll 高频触发造成性能问题:

js
function throttle(fn, delay) {
  let last = 0;
  return function (...args) {
    const now = Date.now();
    if (now - last > delay) {
      last = now;
      fn(...args);
    }
  };
}

container.addEventListener('scroll', throttle(handleScroll, 200));

2. 加载锁

防止重复加载:

js
let isLoading = false;

function loadMore() {
  if (isLoading) return;
  isLoading = true;
  showLoading(true);

  fetchMoreData().then(() => {
    isLoading = false;
    showLoading(false);
  });
}

3. 分页控制

通过 page 参数控制加载页数,后端配合返回分页数据及是否还有更多:

js
let page = 1;
function fetchMoreData() {
  return fetch(`/api/items?page=${page++}`).then(res => res.json()).then(data => {
    renderList(data.items);
    if (!data.hasMore) {
      container.removeEventListener('scroll', handleScroll);
    }
  });
}

✅ 三、进阶方案:IntersectionObserver

使用 IntersectionObserver 监听“加载更多”元素是否出现在视口中

html
<ul id="list"></ul>
<div id="sentinel">加载中...</div>
js
const sentinel = document.getElementById('sentinel');
const observer = new IntersectionObserver(([entry]) => {
  if (entry.isIntersecting) {
    loadMore();
  }
});
observer.observe(sentinel);

这个方法更高效,适用于 React、Vue、原生开发,且不会频繁触发事件。

✅ 四、移动端适配注意点

  • 使用容器 overflow-y: auto 而不是监听 window.scroll,更适配移动端 App/Webview。
  • 设置 -webkit-overflow-scrolling: touch 提升滚动流畅性。
  • 注意兼容 iOS 上 scroll 事件可能有延迟的问题。
  • 如果用 Vue/React,建议封装成组件,如:
vue
<!-- Vue3 示例 -->
<template>
  <div ref="scrollRef" @scroll="handleScroll">
    <slot></slot>
    <div v-if="loading">加载中...</div>
  </div>
</template>