likes
comments
collection
share

大白话详解Intersection Observer API

作者站长头像
站长
· 阅读数 30

大白话详解Intersection Observer API

昨天我写了Vue2 中自定义图片懒加载指令这篇博客,文章数据很好,阅读量可以上千,对于我这个刚写博客一周的新博主来说,是何等的荣幸。

那现在就来更新今天的文章吧,继续延续昨天的文章,昨天的文章有朋友在评论区推荐了Intersection Observer API来实现图片懒加载,那这篇博客我先介绍一下这 API,但这 API 兼容性一般,且完全不兼容 IE,大家在实际项目中谨慎使用。

但在介绍Intersection Observer API之前,首先要先了解另外三个知识点,分别是 IntersectionObserver()构造器IntersectionObserverEntry 对象IntersectionObserverEntry 对象

他们之前的关系比较复杂,大家可以先看看这个整体关系图,以及他们的参数、属性与方法。 大白话详解Intersection Observer API

1.Intersection Observer API 的基本介绍

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

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

1.1 Intersection Observer API 出现的原因

因为在如今网页开发的过程中,常常需要判断某个元素是否进入了"视口"(viewport),即用户能不能看到它。

面对这种相交检测的任务时,过去我们通常会使用Element.getBoundingClientRect()等方法来获取相关元素的位置信息,并且还会用到事件监听

然而事件监听和调用Element.getBoundingClientRect()等 API 都是运行在主线程,因此频繁触发、调用会造成性能问题,而且这种检测方法使用起来比较繁琐

因此官方就提出了Intersection Observer API,该 API 的出现就是为了高效的解决以下两大类问题:

  1. 某个元素是否可见,如:
    • 图片懒加载——当图片滚动到可见时才进行加载
    • 内容无限滚动——当用户滚动到接近底部时直接加载更多,而无需翻页,给用户一种网页可以无限滚动的错觉
  2. 两个元素是否相交,如:
    • 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
    • 在用户看见某个区域时执行任务或播放动画

Intersection Observer API会注册一个回调函数,只会在以下两种情况触发:

  1. 目标元素进入或退出根元素
  2. 交叉比达到阈值时,补充点:
    • 但是该 API 无法提供重叠的像素个数或具体哪个像素重叠,只能设置阈值来进行控制回调函数的调用。

这样,浏览器的主线程就不用在监听元素是否相交,并且IntersectionObserver API是异步进行检测的,也不会占用主线程的资源,从而性能上得到了提升。

1.2 Intersection observer 的重要概念

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

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

2.IntersectionObserver()构造器

IntersectionObserver()构造器用于创建一个 IntersectionObserver 对象,并会将该对像进行放回。 该构造器函数的配置参数如下图所示:

大白话详解Intersection Observer API

其语法如下:

var observer = new IntersectionObserver(callback[, options]);

2.1 IntersectionObserver()构造器的参数与返回值

首先我们先了解一下IntersectionObserver()构造器的参数,其参数有:

  • callback(必选参数) --- 当交叉比超过指定阈值触发回调函数,此函数可接受两个参数:

    1. entries --- 由IntersectionObserverEntry对象组成的数组 但每个被触发的阈值,都或多或少与指定阈值有偏差。
    2. observer --- 返回被调用的IntersectionObserver实例。
  • options(可选参数) --- 用于配置回调函数触发的条件,其参数下还有三个子参数:

    1. root --- 指定根元素。用于检查目标的可见性。默认为浏览器视口
      • 如果指定为 null,也为浏览器视口。
      • 必须是目标元素的父级元素。
    2. rootMargin --- 根元素的扩缩边距。其传值形式与 CSS 中 margin 一样,用于控制根元素每一边的扩缩(单位为 px 或%),从而控制计算根元素和目标元素的交集的区域范围,默认值为 0
    3. threshold --- 阈值,回调函数触发的条件。取值范围为 0.0-1.0,默认值为 0.0
      • 当传入数值类型时,只会触发一次。
      • 当传入数组类型时,可触发多次。
        • 如:[0,0.25,0.5,0.75,1]表示目标元素在跟元素的可见程度每多 25% 就执行一次回调
  • 该函数的返回值: 一个新的IntersectionObserver对像。

    • 该对象会按照设定的阈值来监听目标元素。
    • 调用自身的observe()方法开始对目标元素进行监听。

2.2 IntersectionObserver()构造器的基本语法与异常信息

使用 IntersectionObserver()构造器创建 IntersectionObserver 对象并进行监听的语法如代码下所示:

let options = {
  root: document.querySelector("#root"), //根元素
  rootMargin: "0px", //传值形式类似于css的margin 传一个值则四个边都为0
  threshold: 0, //触发条件 表示目标元素刚进入根元素时触发
};
//IntersectionObserver对象
let observer = new IntersectionObserver(callback, options);
let target = document.querySelector("#target"); //目标元素
observer.observe(target); //开始监听该目标元素
  • 两种异常类型:
    • SyntaxError --- 指定的 rootMargin 不存在或不符合语法。
    • RangeError --- 一个或多个阈值超出了 0.0 到 1.0 的范围。

3.IntersectionObserver 对象

IntersectionObserver 接口(从属于Intersection Observer API)提供了一种异步观察目标元素根元素 交叉状态的方法。

当 IntersectionObserver 对象被创建时,就会被指定所监听的根元素、阀值等信息。一旦 IntersectionObserver 被创建后就无法更改其指定信息。

  • 所以一个给定的观察者对象只能用来监听可见区域的特定变化值;当然你也可以在同一个观察者对象中配置监听多个目标元素。

该对象的属性与方法如下图所示: 大白话详解Intersection Observer API

3.1 IntersectionObserver 对象的属性与方法

3.1.1 三个属性

该对像的三个属性与IntersectionObserver()构造器的 options 参数类似,并且这三个属性都只能读取操作,不能进行更改。

属性说明默认值
root指定根元素。如果传值为 null,则为顶级文档的视窗。顶级文档的视口(一般为 html)
rootMargin根元素的扩缩边距。其传值形式与 CSS 中 margin 一样,用于控制根元素每一边的扩缩(单位为 px 或%),从而控制计算根元素和目标元素的交集的区域范围。单位为 px 或%。默"0px 0px 0px 0px"
thresholds一个包含阈值的数组,并按升序排列,列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发回调函数。0

3.1.2 四个方法

该对象的四个方法如下表:

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

4. IntersectionObserverEntry 对象

IntersectionObserverEntry接口(从属于 Intersection Observer API)描述了目标元素与其根元素容器在某一特定过渡时刻的交叉状态。

IntersectionObserverEntry对像数组作为entries参数传递给IntersectionObserver对像的回调函数中; 此外,这对象数组只能通过调用IntersectionObserver.takeRecords()来获取。

该对象的主要属性如下图所示:

大白话详解Intersection Observer API

4.1 IntersectionObserverEntry 对象的属性

IntersectionObserverEntry 对象的七个属性都是只读属性,如下表所示:

属性说明
target返回目标元素,表示目前该对象正监听的元素
isIntersecting返回一个布尔值,目标元素刚出现在根元素可视区时返回 true;目标元素从根元素可视区消失返回 false;以上两种情况都会触发 callback 函数
boundingClientRect返回目标元素的矩形区域的信息,返回结果与element.getBoundingClientRect()相同
rootBounds返回根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回 null
intersectionRect返回目标元素与视口(或根元素)的交叉区域的信息
intersectionRatio返回目标元素的可见比例,即intersectionRectboundingClientRect的比例,完全可见时为 1,完全不可见时小于等于 0
time返回一个记录从IntersectionObserver的时间原点到交叉被触发的时间的时间戳

5. Intersection Observer API 的兼容性

该 API 的兼容性如下:

大白话详解Intersection Observer API 详情大家可参考CAN I USE - intersectionobserver

6. Intersection Observer API 的简单案列

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

<!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>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .container > div {
        margin: 5px auto;
        width: 100px;
        height: 100px;
        outline: 1px solid red;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
      <div class="item">4</div>
      <div class="item">5</div>
      <div class="item">6</div>
      <div class="item">7</div>
      <div class="item">8</div>
      <div class="item">9</div>
      <div class="item">10</div>
      <div class="item">11</div>
      <div class="item">12</div>
      <div class="item">13</div>
      <div class="item">14</div>
      <div class="item">15</div>
    </div>
    <script>
      //io 为 IntersectionObserver对象 - 由IntersectionObserver()构造器创建
      var io = new IntersectionObserver((entries) => {
        //entries 为 IntersectionObserverEntry对像数组
        entries.forEach((item) => {
          //item 为 IntersectionObserverEntry对像
          // isIntersecting是一个Boolean值,判断目标元素当前是否可见
          if (item.isIntersecting) {
            //div 可见时 进行相关操作
            console.log(item.target.innerText);
            io.unobserve(item.target); //停止监听该div DOM节点
          }
        });
      }); //不传options参数,默认根元素为浏览器视口
      const divArr = [...document.querySelectorAll(".item")];
      divArr.forEach((div) => io.observe(div)); // 遍历监听所有div DOM节点
    </script>
  </body>
</html>

我已在 Vue2 使用Intersection Observer API实现了图片懒加载效果哦,大家可以去看看。Vue2 中自定义图片懒加载指令 2.0

参考博客

结语

这是我目前所了解的知识面中最好的解答,当然也有可能存在一定的误区。

所以如果对本文存在疑惑,可以在评论区留言,我会及时回复的,欢迎大家指出文中的错误观点。

最后码字不易,觉得有帮助的朋友点赞、收藏、关注走一波。

转载自:https://juejin.cn/post/7146441070828584968
评论
请登录