使用Intersection Observer API 检测元素是否出现在可视窗口

news2024/12/17 4:40:25

使用Intersection Observer API 检测元素是否出现在可视窗口

API解读:

Intersection Observer API提供了一种异步检测目标元素与祖先元素或视口(可统称为根元素)相交情况变化的方法。

注意点:因为该 API 是异步的,它不会随着目标元素的滚动同步触发,而IntersectionObserver API是通过requestIdleCallback()实现,即只有浏览器空闲下来,才会执行观察器。

Intersection observer 的重要概念

Intersection observer API 有以下五个重要的概念:

  • 目标(target)元素 — 我们要监听的元素
  • 根(root)元素 — 帮助我们判断目标元素是否符合条件的元素
  • 以下两种情况根元素会默认为顶级文档的视口(一般为 html)。
    • 目标元素不是可滚动元素的后代且不传值时
    • 指定根元素为 null
  • 交叉比(intersection ratio)—目标元素与根根的交集相对于目标元素百分比的表示(取值范围 0.0-1.0)。
  • 阈值(threshold) — 回调函数触发的条件。
  • 回调函数(callback) — 为该 API 配置的函数,会在设定的条件下触发。

用法

是以new的形式声明一个对象,接收两个参数callbackoptions

const io = new IntersectionObserver(callback [,options])

io.observe(DOM)

callback

callback是添加监听后,当监听目标发生滚动变化时触发的回调函数。接收一个参数entries,即IntersectionObserverEntry实例。描述了目标元素与root的交叉状态。具体参数如下:

属性说明
boundingClientRect返回包含目标元素的边界信息,返回结果与element.getBoundingClientRect() 相同
intersectionRatio返回目标元素出现在可视区的比例
intersectionRect用来描述root和目标元素的相交区域
isIntersecting返回一个布尔值,下列两种操作均会触发callback:1. 如果目标元素出现在root可视区,返回true。2. 如果从root可视区消失,返回false
rootBounds用来描述交叉区域观察者(intersection observer)中的根.
target目标元素:与根出现相交区域改变的元素 (Element)
time返回一个记录从 IntersectionObserver 的时间原点到交叉被触发的时间的时间戳

表格中加粗的两个属性是比较常用的判断条件:isIntersecting(是否出现在可视区)和intersectionRatio(出现在可视区的比例)

options

options是一个对象,用来配置参数,也可以不填。共有三个属性,具体如下:

属性说明
root所监听对象的具体祖先元素。如果未传入值或值为null,则默认使用顶级文档的视窗(一般为html)。
rootMargin计算交叉时添加到根(root)边界盒bounding box的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。所有的偏移量均可用像素(px)或百分比(%)来表达, 默认值为"0px 0px 0px 0px"。
threshold一个包含阈值的列表, 按升序排列, 列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发callback。默认值为0。

方法

介绍了这么多配置项及参数,差点忘了最重要的,IntersectionObserver有哪些方法? 如果要监听某些元素,则必须要对该元素执行一下observe

方法说明
observe()开始监听一个目标元素
unobserve()停止监听特定目标元素
takeRecords()返回所有观察目标的IntersectionObserverEntry对象数组
disconnect()使IntersectionObserver对象停止全部监听工作

实际应用

  • 图片懒加载
const imgList = [...document.querySelectorAll('img')]

var io = new IntersectionObserver((entries) =>{
  entries.forEach(item => {
    // isIntersecting是一个Boolean值,判断目标元素当前是否可见
    if (item.isIntersecting) {
      item.target.src = item.target.dataset.src
      // 图片加载后即停止监听该元素
      io.unobserve(item.target)
    }
  })
})
// observe遍历监听所有img节点
imgList.forEach(img => io.observe(img))
  • 埋点曝光

假如有个需求,对一个页面中的特定元素,只有在其完全显示在可视区内时进行埋点曝光。

const boxList = [...document.querySelectorAll('li')]

var io = new IntersectionObserver((entries) =>{
  entries.forEach(item => {
    // intersectionRatio === 1说明该元素完全暴露出来,符合业务需求
    if (item.intersectionRatio === 1) {
      // 。。。 埋点曝光代码
      // do something...
      io.unobserve(item.target)
    }
  })
}, {
  root: null,
  threshold: 1, // 阀值设为1,当只有比例达到1时才触发回调函数
})

// observe遍历监听所有box节点
boxList.forEach(item => io.observe(item))

  • demo:

大家可以在自己电脑运行一下下面的代码,会有更深的理解。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>IntersectionObserver</title>
    <style>
      li {
        width: 200px;
        height: 400px;
        border: 1px solid gray;
      }
    </style>
  </head>
  <body>
    <ul>
      <li>1-aaa</li>
      <li>2-bbb</li>
      <li>3i-ccc</li>
      <li>4i</li>
      <li>5i</li>
      <li>6i</li>
      <li>7i</li>
      <li>8i</li>
      <li>9i</li>
      <li>10i</li>
      <li>l1</li>
      <li>l2</li>
      <li>l3</li>
      <li>l4</li>
      <li>l5</li>
      <li>l6</li>
      <li>l7</li>
      <li>l8</li>
      <li>l9</li>
      <li>10</li>
      <li>21</li>
      <li>22</li>
      <li>23</li>
      <li>24</li>
      <li>25</li>
      <li>26</li>
      <li>27</li>
      <li>28</li>
      <li>29</li>
      <li>30</li>
    </ul>
    <script>
      const imgList = [...document.querySelectorAll("li")];
      const options = {
        root: null,
        rootMargin: "1px",
        thresholds: 1,
      };
      //io 为 IntersectionObserver对象 - 由IntersectionObserver()构造器创建
      const io = new IntersectionObserver((entries) => {
        //entries 为 IntersectionObserverEntry对像数组
        entries.forEach((item) => {
          //item 为 IntersectionObserverEntry对像
          // item.isIntersecting是一个Boolean值,判断目标元素当前是否可见
          if (item.isIntersecting) {
            console.log(item);
            // item.target.src = item.target.dataset.src;
            // li加载后即停止监听该元素
            io.unobserve(item.target);
          }
          // intersectionRatio === 1说明该元素完全暴露出来
          // if (item.intersectionRatio === 1) {
          //   埋点曝光代码
          //   do something...
          //   停止监听该元素
          //   io.unobserve(item.target);
          // }
        });
      }, options); //不传options参数,默认根元素为浏览器视口
      // observe遍历监听所有li节点
      imgList.forEach((li) => io.observe(li));
    </script>
  </body>
</html>

关于如何判断元素是否在可视区域内的其他方法

本地路径

第一种方法:offsetTop、scrollTop

公式: el.offsetTop - document.documentElement.scrollTop <= viewPortHeight

function isInViewPortOfOne (el) {
    // viewPortHeight 兼容所有浏览器写法
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    console.log('top', top)
     // 这里有个+100是为了提前加载+ 100
    return top <= viewPortHeight + 100
}

第二种方法:getBoundingClientRect

  • 返回值是一个 DOMRect 对象,拥有 left, top, right, bottom, x, y, width, 和 height 属性

公式: el.getBoundingClientReact().top <= viewPortHeight

其实, el.offsetTop - document.documentElement.scrollTop = el.getBoundingClientRect().top, 利用这点,我们可以用下面代码代替方法一

function isInViewPortOfTwo (el) {
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const top = el.getBoundingClientRect() && el.getBoundingClientRect().top
    console.log('top', top)
    return top  <= viewPortHeight + 100
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot实现校园交友网站管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校园交友网站管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生…

COSCon'23媒体和社区合作伙伴正式公布!百川相聚,潮汇大海,邀您天府之城共话开源!...

一年一度的开源盛会&#xff0c;COSCon23 第八届中国开源年会&#xff0c;将于10月28~29日&#xff0c;在四川成都市高新区菁蓉汇召开&#xff01;本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01; 如往年一样&#xff0c;作为中国最大的非营利…

独创变频杀毒(血影内核) 瑞星杀毒软件V16保驾护航

下载地址&#xff1a;https://user.qzone.qq.com/512526231/main

MySQL知识总结(内附超详细知识框架图)

MySQL知识总结 博友们&#xff0c;你们好&#xff01;博主最近对MySQL相关的知识进行了复盘&#xff0c;并通过思维导图的方式提取出了MySQL的核心知识点&#xff0c;现将复盘结果分享给大家&#xff0c;希望能够对大家学习MySQL有所帮助。 下面博主将MySQL各大模块的思维导图…

CDN是如何一步步壮大到现在这样的

当我们浏览网页、观看在线视频或下载文件时&#xff0c;CDN&#xff08;内容分发网络&#xff09;已经成为网络世界中不可或缺的一部分。本文将探讨CDN的发展历程&#xff0c;其工作原理&#xff0c;以及它如何利用不同地区来提供更快速、可靠的内容交付服务。 CDN的发展历程 过…

HTML5+CSS3+JS小实例:带密码灯照射的登录界面

实例:带密码灯照射的登录界面 技术栈:HTML+CSS+JS 字体图标库:Font Awesome 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name=&…

SOLIDWORKS® 2024 新功能 - SIMULATION

1、增强型轴承接头 • 通过指定压缩、拉伸和弯曲的刚度&#xff0c;轻松创建自定义轴承接头。 • 通过向非线性和大型位移算例添加自定义条件&#xff0c;提高模拟精度。 优点 使用功能强大的接口&#xff0c;更轻松、更准确地设置模拟过程&#xff0c;并加快模拟速度。 2、…

计算机行业已经进入寒冬?云计算帮你解决就业难题!

近几年国内外互联网行业都有大动作&#xff0c;国内外互联网企业都开始了裁员。 “谷歌宣布解雇1.2万名员工&#xff0c;占总员工数的6%” “微软宣布计划在第三财季裁员1万人” “Meta开启两轮万人裁员&#xff0c;总计裁员约2.1万” “据传阿里即将裁员25%” “OPPO宣布哲库…

SpringBoot整合阿里云OSS对象存储

文章目录 1、OSS介绍及开通1.1、阿里云OSS简介1.2、开通OSS 2、创建存储空间bucket及密钥获取2.1、创建存储空间2.2、获取密钥 3、OSS快速入门案例4、在springboot项目中整合4.1、将oss配置放到yml文件中4.2、创建Oss属性类&#xff0c;接收yml文件中的属性4.3、封装文件上传功…

Redis 主从复制和哨兵监控,实现Redis高可用配置

文章目录 一、概述二、主从复制模拟说明三、准备配置文件四、启动Redis实例五、主从复制配置5.1 命令方式启用和取消主从复制5.2 配置文件方式启用和取消主从复制5.3 测试主从复制5.4 有其主从复制的其他参数配置 六、Sentinel 配置6.1 Sentinel 的作用6.2 Sentinel 监控说明6.…

现货白银指标分析根本没用!?

在现货白银市场上&#xff0c;RSI、PAR、抛物线、动力指标MOM等的分析工具大行其道&#xff0c;受到不少投资者的欢迎&#xff0c;其实这些指标都是由于美国人威尔斯威尔德发明&#xff0c;但它后来有发表文章推翻了这些分析工具的好处&#xff0c;并推出了另一套崭新理论去取代…

虹科直播 | CDS网络与数据安全专题技术直播重磅来袭,11.2起与您精彩相约

文章来源&#xff1a;虹科网络安全 阅读原文&#xff1a;https://mp.weixin.qq.com/s/T-CgU28hmYy4YV5SV9QGhg 虹科数据加密解决方案 虹科终端安全防护方案 虹科是在各细分专业技术领域内的资源整合及技术服务落地供应商&#xff0c;虹科网络安全事业部的宗旨是&#xff1a;让…

【牛牛送书 | 第二期】《ChatGPT 驱动软件开发:AI 在软件研发全流程中的革新与实践》

目录 前言&#xff1a; 本书目录&#xff1a; 内容简介&#xff1a; 专家评价&#xff1a; 适合对象&#xff1a; 送书规则&#xff1a; 前言&#xff1a; 现如今&#xff0c;随着计算机技术的不断发展和互联网的普及&#xff0c;我们已经迈入了一个高效的信息处理和传…

批量管理文件,轻松实现翻译与重命名,一键操作高效便捷!

在工作中&#xff0c;我们经常需要处理大量的文件&#xff0c;而文件的翻译和重命名是常见的需求。为了帮助您更高效地管理文件&#xff0c;我们特别推出一款全新的批量文件管理工具&#xff0c;让您轻松实现文件的翻译和重命名&#xff0c;提高工作效率&#xff01; 首先第一步…

【收藏】药物专利信息查询方法-经典实操案例!

生物医药领域在专利行业中&#xff0c;一直是独特的存在。药物专利在各国之间有不同的登记要求&#xff0c;如何在这种查询方式诸多局限的情况下&#xff0c;检索得更全更准呢&#xff1f; 作为一名医药行业的IPR&#xff0c;经常需要调研药物原研专利。 大家所熟知的最快捷的…

Boris FX Optics 2024:打造电影级视觉特效的终极工具

在一部电影中&#xff0c;视觉特效是不可或缺的一部分&#xff0c;它能够将观众带入一个奇妙的世界&#xff0c;让他们沉浸在故事中。然而&#xff0c;创建这些特效并不容易&#xff0c;需要使用专业的软件来完成。今天&#xff0c;我们将向您介绍一款名为Boris FX Optics 2024…

【Python生活脚本】过滤重复汉字,特别适用于制作tft字库

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-10-27 ❤️❤️ 本篇更新记录 2023-10-27 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…

Python + requests实现接口自动化框架!

为什么要做接口自动化框架 1、业务与配置的分离 2、数据与程序的分离&#xff1b;数据的变更不影响程序 3、有日志功能&#xff0c;实现无人值守 4、自动发送测试报告 5、不懂编程的测试人员也可以进行测试 正常接口测试的流程是什么&#xff1f; 确定接口测试使用的工具…

Java中的类和对象 (二)

目录 1.封装 1.1 封装的概念 1.2 访问限定符 1.3 封装扩展之包 1.3.1 包的概念 1.3.2 导入包中的类 1.3.3 自定义包 1.3.4 包的访问权限控制举例 1.3.5 常见的包 2. static成员 2.1 static修饰成员变量 2.2 static修饰成员方法 2.3 static成员变量初始化 …

Python+Pytest+Request【第一章】接口框架介绍

接口框架介绍 businesscommonconfigoutputstest_reporttestcase business business目录下面我们会放一些底层接口信息&#xff0c;会将封装好的一些方法组装成一个动作&#xff0c;你可以理解为一个组装车间&#xff0c;把已经写好的零部件组合起来&#xff0c;组成一个车子的…