前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >移动端滚动分页解决方案

移动端滚动分页解决方案

作者头像
万少
修改2025-02-10 17:19:40
修改2025-02-10 17:19:40
5800
代码可运行
举报
运行总次数:0
代码可运行

什么是移动端滚动分页

当用户滑动页面到底部时,便会触发页面的加载分页数据功能

2021-07-14221433
2021-07-14221433

解决方案

解决方案

目前主流的解决方案主要有两个,scrollIntersectionObserver

  1. scroll 是页面滚动事件,当页面滚动时,判断滚动条距离是否触底,如果是,便执行分页逻辑
  2. IntersectionObserver 是一个用于观察元素可见性变化的API。它可以用于检测元素是否进入或离开视口(viewport),或者与其他元素发生交叉

scroll

目前m端淘宝采用的是 scroll,它的特点是兼容性够好。几乎全部的浏览器都支持常用,缺点便是事件触发太频繁,因为每一滚动滚动都需要进行判断。

当我们移除掉淘宝 body元素上的scroll事件时,分页逻辑便失效了。

2021-07-142214333
2021-07-142214333

如果我们自己利用 scroll事件,实现一个分页事件,也是不难的。主要思路如下:

image-20230629235507781
image-20230629235507781

提供的示例代码如下

代码语言:javascript
代码运行次数:0
复制
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    li {
      height: 50px;
      border: 1px solid #000;
    }

    p {
      height: 100px;
      background-color: sandybrown;
    }

    .loading::before {
      background-color: rgba(0, 0, 0, .6);
      position: fixed;
      width: 100vw;
      height: 100vh;
      z-index: 0;
      content: "";

    }

    .loading::after {
      content: "加载中...";
      font-size: 30px;
      color: #fff;
      width: 400px;
      height: 100px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50px;

      position: fixed;
      top: 50%;
      left: 50%;
      background-color: seagreen;
      transform: translate(-50%, -50%);
    }



    body {
      height: 100vh;
      overflow: auto;
      background-image: linear-gradient(yellow, pink, skyblue);
    }
  </style>
</head>

<body>
  <ul></ul>
  <p>加载中</p>

  <script>
    const p = document.querySelector("p"); // 获取第一个 <p> 元素
    const ul = document.querySelector("ul"); // 获取第一个 <ul> 元素
    loadData(); // 调用 loadData 函数加载数据

    window.addEventListener("scroll", function () {
      const { clientHeight } = document.body; // 获取页面可视区域的高度
      const { scrollTop } = document.documentElement; // 获取页面滚动的垂直距离
      const { scrollHeight } = document.documentElement; // 获取页面的总高度
      if (scrollHeight - scrollTop - clientHeight === 0) {
        // 如果滚动到底部
        loadData(); // 调用 loadData 函数加载数据
      }
    });

    async function loadData() {
      if (document.body.classList.contains("loading")) {
        // 如果页面正在加载数据,则返回
        return;
      }
      console.log("开始分页");
      document.body.classList.add("loading"); // 给 body 元素添加 loading 类,表示正在加载数据
      await sleep(2000); // 等待 2000 毫秒
      let str = "";
      for (let index = ul.childElementCount; index < ul.childElementCount + 100; index++) {
        // 生成 li 元素的内容
        str += `<li>${index + 1}</li>`;
      }
      ul.innerHTML += str; // 将生成的 li 元素添加到 ul 元素中
      document.body.classList.remove("loading"); // 移除 body 元素的 loading 类,表示数据加载完成
    }

    function sleep(time, fn) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve();
        }, time);
      });
    }
  </script>
</body>

</html>

效果如下

2023-06-30001107
2023-06-30001107

IntersectionObserve

IntersectionObserver 是一个 JavaScript API,用于异步监测目标元素与其祖先或视口之间的交叉状态。通过使用 IntersectionObserver,可以轻松地检测目标元素是否进入或离开视口,或者与其祖先元素交叉的程度。

使用 IntersectionObserver 的好处是它可以异步地观察元素的交叉状态,而不会导致性能问题。缺点是兼容性没有scroll 好,但是主流浏览器也支持了。

image-20230630001704333
image-20230630001704333

以下是它的基本代码

代码语言:javascript
代码运行次数:0
复制
// 创建一个 IntersectionObserver 实例
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // 目标元素进入视口
      console.log('目标元素进入视口');
    } else {
      // 目标元素离开视口
      console.log('目标元素离开视口');
    }
  });
});

// 监听目标元素
const targetElement = document.querySelector('#target');
observer.observe(targetElement);

目前vant4中的Lazyload 懒加载组件底层使用的技术是 IntersectionObserve

image-20230630001541395
image-20230630001541395

如果我们要利用 IntersectionObserve 实现一个自己的分页事件,也是挺便捷的。

代码语言:javascript
代码运行次数:0
复制
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    li {
      height: 50px;
      border: 1px solid #000;
    }

    p {
      height: 100px;
      background-color: sandybrown;
    }

    .loading::before {
      background-color: rgba(0, 0, 0, .6);
      position: fixed;
      width: 100vw;
      height: 100vh;
      z-index: 0;
      content: "";

    }

    .loading::after {
      content: "加载中...";
      font-size: 30px;
      color: #fff;
      width: 400px;
      height: 100px;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50px;

      position: fixed;
      top: 50%;
      left: 50%;
      background-color: seagreen;
      transform: translate(-50%, -50%);
    }



    body {
      height: 100vh;
      overflow: auto;
      background-image: linear-gradient(yellow, pink, skyblue);
    }
  </style>
</head>

<body>
  <ul></ul>
  <p>加载中</p>

  <script>
    // 选择第一个 <p> 元素
    const p = document.querySelector("p");

    // 选择第一个 <ul> 元素
    const ul = document.querySelector("ul");

    // 创建一个 IntersectionObserver 对象
    const ob = new IntersectionObserver(function (entries) {
      // 获取第一个观察目标的 isIntersecting 属性
      const isIntersecting = entries.shift().isIntersecting;

      // 如果目标元素进入视口,执行 loadData() 函数
      isIntersecting && loadData();
    }, {
      // 设置触发回调函数的阈值为 0.1
      threshold: 0.1
    });

    // 将 <p> 元素添加到 IntersectionObserver 中进行观察
    ob.observe(p);


    async function loadData() {
      if (document.body.classList.contains("loading")) {
        return
      }
      console.log("开始分页");
      document.body.classList.add("loading")
      await sleep(2000)
      let str = "";
      for (let index = ul.childElementCount; index < ul.childElementCount + 100; index++) {
        str += `<li>${index + 1}</li>`
      }
      ul.innerHTML += str
      document.body.classList.remove("loading")

    }

    function sleep(time, fn) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve();
        }, time);
      })

    }
  </script>
</body>

</html>

效果如下

2023-06-30001107
2023-06-30001107

总结

目前主流的解决方案主要有两个,scrollIntersectionObserver

  1. scroll 是页面滚动事件,当页面滚动时,判断滚动条距离是否触底,如果是,便执行分页逻辑 优点是兼容性好,缺点是事件触发频繁,性能差
  2. IntersectionObserver 是一个用于观察元素可见性变化的API。它可以用于检测元素是否进入或离开视口(viewport),或者与其他元素发生交叉。优点时性能好,缺点是兼容性比 scroll 稍差。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是移动端滚动分页
  • 解决方案
  • scroll
  • IntersectionObserve
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档