移动端滚动分页解决方案

简介: 移动端滚动分页解决方案

什么是移动端滚动分页

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

QZ`}9XV2)I)KVE55K2%ZO)L.png

解决方案

解决方案

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

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

scroll

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

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

OTFU$`B%G87C2XIUZ]$[~M4.png


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

RWTJAA$8TTKLHX{BMOWT$`V.png


提供的示例代码如下

<!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>


效果如下

]O]H%H`@{3AZ83CO%3G6KDW.png

IntersectionObserve

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

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

X9X`@8L%{C(YOWUO$J9IUCJ.png

以下是它的基本代码

// 创建一个 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

YZ6MGX_JU~$5F9)]U6RB@8N.png


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

<!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>



效果如下

KZZDZB8_K)6XZVR4X38RG]U.png

总结

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

  1. scroll 是页面滚动事件,当页面滚动时,判断滚动条距离是否触底,如果是,便执行分页逻辑 优点是兼容性好,缺点是事件触发频繁,性能差
  2. IntersectionObserver 是一个用于观察元素可见性变化的API。它可以用于检测元素是否进入或离开视口(viewport),或者与其他元素发生交叉。优点时性能好,缺点是兼容性比 scroll 稍差。
目录
相关文章
|
6月前
|
小程序
微信小程序实现上拉加载分页列表的性能优化
微信小程序实现上拉加载分页列表的性能优化
|
4月前
|
小程序
微信小程序—页面滑动,获取可视区域数据
微信小程序—页面滑动,获取可视区域数据
63 2
|
4月前
|
JSON 小程序 数据库
【微信小程序-原生开发】实用教程14 - 列表的分页加载,触底加载更多(含无更多数据的提醒和显示,自定义组件)
【微信小程序-原生开发】实用教程14 - 列表的分页加载,触底加载更多(含无更多数据的提醒和显示,自定义组件)
121 0
|
6月前
|
数据库
Uniapp 横向滚动抽奖页面 组件 引用即可 全端
Uniapp 横向滚动抽奖页面 组件 引用即可 全端
198 0
|
小程序 JavaScript
微信小程序横向滚动卡片列表模板
微信小程序横向滚动卡片列表模板
301 0
移动端横向滚动列表
移动端横向滚动列表
93 0
|
自然语言处理 JavaScript 前端开发
动态滑动图片验证码组件(支持多语言,移动端)
动态滑动图片验证码组件(支持多语言,移动端)
动态滑动图片验证码组件(支持多语言,移动端)
|
前端开发 JavaScript
前端开发中,滑动展现日志麻烦?这个组件来帮你
前端开发中,滑动展现日志麻烦?这个组件来帮你
531 0
前端开发中,滑动展现日志麻烦?这个组件来帮你
|
缓存 前端开发 数据可视化
前端基础向--空表格处理与分页调整,优化用户体验
前端基础向--空表格处理与分页调整,优化用户体验
192 0