通过IntersectionObserver实现图片下拉加载(瀑布流布局)

效果展示:

瀑布流上拉加载

目录结构

html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>demo2</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="grid"></div>
    <div class="spin"></div>
    <script src="./index.js"></script>
  </body>
</html>

css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: #f5f5f5;
}

.grid {
  width: 80%;
  margin: 50px auto;
}

.grid img {
  animation: scale 1s;
}

@keyframes scale {
  0% {
    transform: scale(0);
    opacity: 0;
  }
}

.spin {
  width: 20px;
  height: 20px;
  margin: 0 auto;
  padding: 20px;
  border: 7px dashed #4b9cdb;
  border-radius: 100%;
  animation: loading 1.5s 0.3s cubic-bezier(0.17, 0.37, 0.43, 0.67) infinite;
  margin-bottom: 100px;
}

@keyframes loading {
  0% {
    transform: rotate(0deg);
  }

  50% {
    transform: rotate(180deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

js

/**
 * 实现 Masonry 布局
 */
class Masonry {
  constructor(options) {
    // 获取布局容器,假定该容器内部的所有元素都是图片元素
    this.container = options.container;
    // 获取列数
    this.columnNumber = options.columnNumber || 4;
    // 获取行列间隙
    this.gap = options.gap || 10;
    // 设置布局容器为相对定位,因为内部的所有元素将使用绝对定位
    this.container.style.position = 'relative';
    // 初始化列高
    this.columnHeights = new Array(this.columnNumber).fill(0);
    // 获取列宽
    this.columnWidth = this._getColumnWidth();
    this.defaultImagePath = './default.png';
  }
  /**
   * 计算列宽
   */
  _getColumnWidth() {
    const containerWidth = this.container.clientWidth;
    const totalGapWidth = (this.columnNumber - 1) * this.gap;
    return (containerWidth - totalGapWidth) / this.columnNumber;
  }

  _onAllImageLoaded(imgElements) {
    return new Promise((resolve) => {
      let imgLoadCounter = 0;
      if (imgLoadCounter === imgElements.length) {
        resolve();
        return;
      }
      const checkAndResolve = () => {
        imgLoadCounter++;
        if (imgLoadCounter === imgElements.length) {
          resolve();
        }
      };

      imgElements.forEach((img) => {
        // 如果图片已经加载,直接增加计数器
        if (img.complete) {
          checkAndResolve();
        } else {
          img.onload = checkAndResolve;

          img.onerror = () => {
            img.onerror = null; // 避免在加载默认图片时触发错误循环
            img.src = this.defaultImagePath;
          };
        }
      });
    });
  }

  /**
   * 对图片元素进行布局
   * @param {Array<HTMLImageElement>} imgElements
   */
  _layout(imgElements) {
    imgElements.forEach((img) => {
      img.style.width = `${this.columnWidth}px`;
      const columnIndex = this.columnHeights.indexOf(
        Math.min(...this.columnHeights)
      );
      img.style.position = 'absolute';
      img.style.left = `${columnIndex * (this.columnWidth + this.gap)}px`;
      img.style.top = `${this.columnHeights[columnIndex]}px`;

      this.columnHeights[columnIndex] += img.clientHeight + this.gap;
      this.container.style.height = `${Math.max(...this.columnHeights)}px`;
    });
  }

  /**
   * 追加图片元素到容器中,并对新加入的图片完成布局
   * @param {Array<HTMLImageElement>} imgElements
   */
  async append(imgElements) {
    await this._onAllImageLoaded(imgElements);
    imgElements.forEach((img) => {
      this.container.appendChild(img);
    });
    this._layout(imgElements);
  }
}

function loadImages(number = 10) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const imgElements = [];

      for (let i = 0; i < number; i++) {
        const img = new Image();
        const randomX = Math.floor(Math.random() * (800 - 200 + 1)) + 200;
        const randomY = Math.random();
        img.src = `https://picsum.photos/400/${randomX}?r=${randomY}`;
        imgElements.push(img);
      }

      resolve(imgElements);
    }, 1000);
  });
}

const masonry = new Masonry({
  container: document.querySelector('.grid'),
  columnNumber: 4,
  gap: 10,
});
let isLoading = false;
async function loadMoreImages(number = 10) {
  if (isLoading) {
    return;
  }
  isLoading = true;
  const imgs = await loadImages(number);
  masonry.append(imgs);
  isLoading = false;
}
loadMoreImages(30);
const ob = new IntersectionObserver(
  (entries) => {
    if (entries[0].isIntersecting) {
      loadMoreImages(10);
    }
  },
  {
    threshold: 0,
  }
);

ob.observe(document.querySelector('.spin'));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/272178.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣刷题记录(18)LeetCode:474、518、377、322

目录 474. 一和零 518. 零钱兑换 II 377. 组合总和 Ⅳ 322. 零钱兑换 总结&#xff1a; 474. 一和零 这道题和前面的思路一样&#xff0c;就是需要将背包扩展到二维。 class Solution { public:int findMaxForm(vector<string>& strs, int m, int n) {vector&l…

KNN与KD树博客总结

目录 总结小结&#xff1a; 总结 原始篇&#xff1a;KNN算法及其优缺点算法思想改进篇&#xff1a;KD树&#xff08;KNN的plus版算法实现第一篇&#xff1a;平衡二叉树的构建&#xff08;递归算法实现第二篇&#xff1a;KD树的构建&#xff08;递归算法实现第三篇&#xff1a;…

开源持续测试平台Linux MeterSphere本地部署与远程访问

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…

windows安全配置实验手册

访问控制策略&#xff08;L1940520022J&#xff09; 预备知识 Windows 7中&#xff0c;不仅有面向软件的限制方法&#xff0c;还增加了一种名为AppLocker的访问控制策略&#xff08;仅适用于企业版和旗舰版&#xff09;。 实验环境 操作系统类型&#xff1a;windows 7。 实…

【问题记录-ASIO】Audition多通道ASIO驱动提示“(不工作)“问题

一&#xff0c;问题现象 在使用Audition打开多通道工程&#xff0c;使用ASIO驱动&#xff0c;却发现设备提示“不工作”&#xff0c;如下图所示&#xff1a; 二&#xff0c;解决方法 2.1 声卡设备枚举确认 首先确认声卡设备枚举是否成功&#xff0c;如果没有枚举成功&…

【SpringCloud笔记】(10)消息总线之Bus

Bus 前言 戳我了解Config 学习Config中我们遇到了一个问题&#xff1a; 当我们修改了GitHub上配置文件内容&#xff0c;微服务需要配置动态刷新并且需要手动向客户端发送post请求刷新微服务之后才能获取到GitHub修改过后的内容 假如有多个微服务客户端3355/3366/3377…等等…

将本地镜像推送到阿里云

文章目录 创建仓库镜像登录 并上传下载上传的 创建仓库镜像 利用下面的脚本进行配置 登录 并上传 [roothadoop100 ~]# docker login --username13thm registry.cn-hangzhou.aliyuncs.com Password: [roothadoop100 ~]# docker tag ba78e6d6845c registry-vpc.cn-hangzhou.al…

C++-类和对象(1)

1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间的交互完 成。…

一文读懂铭文赛道新手攻略

近期&#xff0c;加密领域的热点焦点不断涌现&#xff0c;但毫无疑问&#xff0c;"铭文"这个词汇已经成为了近两个月内广受瞩目的关键词之一。像ORDI、SATS、RATS等铭文项目在比特币区块链上获得了惊人的增长&#xff0c;为持有者带来了巨大的财富效应。铭文热潮已经…

使用 Fiddler+Linux 日志 + 数据库,搞懂3个问题,强势回怼开发!

测试过程中有没有遇到过什么问题是你解决的&#xff1f; 遇到bug怎么分析是前端bug还是后端bug&#xff1f; 测试的时候怎么确认你的测试结果是正确的&#xff1f; 定位分析问题的能力是测试不可或缺的&#xff0c;而且这个能力需要项目经验积累以及需要丰富的知识面才能达到…

k8s---kubernets

目录 一、Kurbernetes 1.2、K8S的特性&#xff1a; 1.3、docker和K8S&#xff1a; 1.4、K8S的作用&#xff1a; 1.5、K8S的特性&#xff1a; 二、K8S集群架构与组件&#xff1a; 三、K8S的核心组件&#xff1a; 一、master组件&#xff1a; 1、kube-apiserver&#xff1…

NET中使用SQLSugar操作sqlserver数据库

目录 一、SqlSugar是什么&#xff1f; 二、迁移和建表 1.建立实体 2.创建上下文类 3.在Program中添加SqlSugar服务 4.在控制器中注入上下文类 三、简单实现CURD功能 总结 一、SqlSugar是什么&#xff1f; SqlSugar是一款老牌 .NET 开源ORM框架。 主要特点&#xff1a…

JVM入门到入土-Java虚拟机寄存器指令集与栈指令集

JVM入门到入土-Java虚拟机寄存器指令集与栈指令集 HotSpot虚拟机中的任何操作都需要入栈和出栈的步骤。 由于跨平台性的设计&#xff0c;Java的指令都是根据栈来设计的。不同平台CPU架构不同&#xff0c;所以不能设计为基于寄存器的。优点是跨平台&#xff0c;指令集小&#x…

华为设备VRP系统管理

为了满足企业业务对网络的需求&#xff0c;网络设备中的系统文件需要不断进行升级。另外&#xff0c;网络设备中的配置文件也需要时常进行备份&#xff0c;以防设备故障或其他灾害给业务带来损害。在升级和备份系统文件或配置文件时&#xff0c;经常会使用FTP和TFTP来传输文件。…

系统学习Python——装饰器:函数装饰器-[跟踪调用]

分类目录&#xff1a;《系统学习Python》总目录 如下的代码定义并使用了一个函数装饰器&#xff0c;统计对被装饰函数的调用次数&#xff0c;并且针对每一次调用打印跟踪信息&#xff1a; class tracer:def __init__(self, func):self.calls 0self.func funcdef __call__(se…

【Linux驱动】最基本的驱动框架 | LED驱动

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;最基本的驱动框架⚽驱动程序框架⚽编程 &#x1f3c0;LED驱动⚽配置GPIO⚽编程…

Python 高级(四):线程池 ThreadPoolExecutor

大家好&#xff0c;我是水滴~~ 当涉及到需要同时处理多个任务的情况时&#xff0c;使用线程池是一种高效的方法。Python提供了concurrent.futures模块&#xff0c;其中的ThreadPoolExecutor类使得使用线程池变得非常方便。本文将详细介绍Python线程池的概念、使用方法和示例代…

【网络安全 | SQL注入】一文讲清预编译防御SQL注入原理

在防止SQL注入的方法中&#xff0c;预编译是十分有效的&#xff0c;它在很大程度上解决了SQL注入问题。 SQL注入简析 数据库查询语句未对SQL注入做任何防护时&#xff0c;语句基本如下&#xff1a; $name$_POST[name]; $pass$_POST[pass]; $sql"SELECT * FROM user W…

展望2024的区块链世界,铭文将是绕不开的话题

近期&#xff0c;加密领域的热点焦点不断涌现&#xff0c;但毫无疑问&#xff0c;"铭文"这个词汇已经成为了近两个月内广受瞩目的关键词之一。像ORDI、SATS、RATS等铭文项目在比特币区块链上获得了惊人的增长&#xff0c;为持有者带来了巨大的财富效应。铭文热潮已经…

图片批量处理:图片批量缩放,高效调整尺寸的技巧

在数字媒体时代&#xff0c;图片处理已是日常生活和工作中不可或缺的一部分。有时候要批量处理图片&#xff0c;如缩放图片尺寸&#xff0c;以满足不同的应用需求。现在一起来看看办公提效式具如何高效的将图片批量处理方法&#xff0c;快速、准确地批量调整图片尺寸操作。 下…