深入浅出详解Intersection Observer交叉观察器 API

原文地址:原文连接

一、前言

过去,要检测一个元素是否可见或者两个元素是否相交并不容易,很多解决办法不可靠或性能很差。然而,随着互联网的发展,这种需求却与日俱增,比如,下面这些情况都需要用到相交检测:
在页面滚动时“懒加载”图像或其他内容。
实现“无限滚动”网站,在滚动过程中加载和显示越来越多的内容,这样用户就不必翻页了。
报告广告的可见度,以便计算广告收入。
根据用户是否能看到结果来决定是否执行任务或动画进程。
视频的播放和暂停。

过去实施相交检测时,需要调用事件处理程序和循环方法,如 Element.getBoundingClientRect() 来为每个受影响的元素建立所需的信息。由于所有这些代码都在主线程上运行,因此即使是其中的一行代码也会导致性能问题。当网站加载这些程序时,情况会变得非常糟糕,体验非常不好。

直到 Intersection Observer API 的出现!

Intersection Observer API(交叉观察器API)是一种JavaScript的API,它提供了一种异步观察目标元素与祖先元素(或顶级文档的视口)交叉状态变化的方法。这个API主要用于高效解决在网页开发中需要频繁判断元素是否进入“视口”(viewport)的问题,比如实现懒加载、无限滚动、可视化统计、视频播放等交互效果,同时减少性能开销,提升用户体验。

二、基本用法

交叉观察器 API 允许你配置一个回调函数,当以下情况发生时会被调用:

目标元素与设备视口或指定元素相交。在交叉观察器 API 中,指定元素被称为根元素或根。

观察器(Observer)第一次监听观察目标元素。

通常情况下,需要观察目标元素最近的可滚动祖先的交集变化,如果目标元素不是可滚动元素的后代,则需要观察设备视口的交集变化。要观察相对于设备视口的交集,请为 root 选项指定 null。无论你是使用视口还是其他元素作为根元素,API 的工作方式都是一样的,只要目标元素的可见性发生变化,与根元素的交集达到所需的程度,就会执行你提供的回调函数。

目标元素与其根元素的交集程度就是交叉比。它表示目标元素可见的百分比,数值介于 0.0 和 1.0 之间。

2.1 创建交叉观察器
通过调用 IntersectionObserver 构造函数,创建交叉观测器,并将回调函数传给它,当一个方向或另一个方向越过阈值时,就运行该函数。

let options = {
  root: document.querySelector("#scrollArea"),
  rootMargin: "0px",
  threshold: 1.0,
};

let observer = new IntersectionObserver(callback, options);

传递到 IntersectionObserver() 构造函数的 options 对象,可以控制在什么情况下调用观察器的回调。它有以下字段:

root:用作视口的元素,用于检查目标的可见性。必须是目标的祖先。如果未指定或为 null,则默认为浏览器视口。

rootMargin:根周围的边距。其值可以类似于 CSS margin 属性,例如 “10px 20px 30px 40px”(上、右、下、左)。这些值可以是百分比。在计算交叉点之前,这组值用于增大或缩小根元素边框的每一侧。默认值为全零。

threshold:一个数字或一个数字数组,表示目标可见度达到多少百分比时,观察器的回调就应该执行。如果只想在能见度超过 50% 时检测,可以使用 0.5 的值。如果希望每次能见度超过 25% 时都执行回调,则需要指定数组 [0, 0.25, 0.5, 0.75, 1]。默认值为 0,这意味着只要有一个像素可见,回调就会运行。值为 1.0 意味着在每个像素都可见之前,阈值不会被认为已通过。

2.2 回调函数
回调函数在交叉状态变化时执行,接收两个参数:一个entries数组和一个observer对象。entries数组中的每个元素都是一个IntersectionObserverEntry对象,表示目标元素与根元素的交叉状态信息。

const callback = (entries, observer) => {  
  entries.forEach(entry => {  
    if (entry.isIntersecting) {  
      // 元素进入视口  
      doSomething()
    } else {  
      // 元素离开视口  
      doSomething() 
    }  
  });  
};

以图片懒加载为例(见下文):

图片元素进入视口entries的信息:
图片元素进入视口entries的信息
图片元素未进入或离开视口entries的信息:
在这里插入图片描述

observer打印信息:在这里插入图片描述

2.3 观察目标元素

const ob = new IntersectionObserver();
ob.observe(targetElement);

使用observe方法将目标元素添加到观察器的观察列表中,targetElement代表需要被观察的目标元素。

2.4 停止观察
如果需要停止观察某个目标元素,可以使用unobserve方法。

const ob = new IntersectionObserver();
ob.unobserve(targetElement);

2.5 终止所有观察
disconnect()方法终止对所有目标元素可见性变化的观察。

const ob = new IntersectionObserver();
ob.disconnect();

2.6 IntersectionObserverEntry对象

  • boundingClientRect:目标元素的矩形区域的信息。

  • intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例。

  • intersectionRect:目标元素与视口(或根元素)的交叉区域的信息。

  • rootBounds:根元素的矩形区域的信息。

  • isIntersecting:目标元素是否与视口(或根元素)交叉。

  • target:被观察的目标元素。

  • time:可见性发生变化的时间戳。

三、实现图片懒加载功能

<div class="container">
    <div class="img-item">
        <img src="./img/default.png" alt="" data-src="./girl/img-1.jpeg" />
    </div>
    <div class="img-item">
        <img src="./img/default.png" alt="" data-src="./girl/img-2.jpeg" />
    </div>
    <div class="img-item">
        <img src="./img/default.png" alt="" data-src="./girl/img-3.jpeg" />
    </div>
    //还有好多张的
    ......
</div>
.container {
    width: 900px;
    margin: 0 auto;
}
.container .img-item {
    display: inline-block;
    width: 17%;
    height: 200px;
    margin: 10px 1%;
}
.container .img-item img {
    width: 100%;
    height: 100%;
}

data-src 属性是真实图片的URL,而 img 标签的 src 属性是默认图片占位符。

const options = {
    root: null,
    // rootMargin: '0px',
    threshold: 0.5
}
// 创建观察器
const ob = new IntersectionObserver((entries, observer) => {
    // 循环每个元素观察其状态
    for (const entry of entries) {
        // 元素进入视口
        if(entry.isIntersecting) {
            const img = entry.target;
            // 把data-src的值赋值给src
            img.src = img.dataset.src;
            // 已经给src赋过值的,停止观察改元素
            ob.unobserve(img);
        }
    }
}, options);

// 获取所有懒加载元素
const imgs = document.querySelectorAll('img[data-src]');
// 循环给每个懒加载元素添加观察器
imgs.forEach(item => {
    ob.observe(item);
})

在这里插入图片描述

四、实现滚动加载更多

创建观察器,获取页面下方加载更多的loading元素,并给该元素添加到观察器中,当观察到下面加载更多的loading元素进入视口,调用loadMoreImages方法加载更多图片。

// 调用接口请求图片
let imgList = [];
async function loadMoreImages(size = 10) {
    // 加入返回的结果为res.data
    imgList = [...imgList, ...res.data];
    isLoading = false;
}
loadMoreImages(10)

//创建观察器
const ob = new IntersectionObserver((entries) => {
    // 当获取加载更多的loading元素进入视口,调用loadMoreImages方法
    const entry = entries[0];
    if(entry.isIntersecting) {
        loadMoreImages(10)
    }
}, {
    threshold: 0
})

// 获取加载更多的loading元素
const spin = document.querySelector('.spin');
ob.observe()

五、实现视频自动播放

经常刷某日头条、某瓜视频等网页时,留心观察会发现,当视频完全进入视口或部分进入视口时视频自动播放,当视频离开视口部分时会停止播放。使用Intersection Observer API实现这个效果就相当容易了。

<!DOCTYPE html>
<html>
  <head>
      <style>
          video {
              width: 100%;
              height: 500px;
              margin-bottom: 20px;
          }
      </style>
  </head>
  <body>
      <video controls loop>
          <source src="./video/video-1.mov" type="video/mp4">
      </video>
      <video controls loop>
          <source src="./video/video-4.mov" type="video/mp4">
      </video>
      <video controls loop>
          <source src="./video/video-3.mov" type="video/mp4">
      </video>
  </body>
  <script type="text/javascript">
      const videos = document.querySelectorAll('video');
      //创建观察器
      const ob = new IntersectionObserver((entries) => {
          for (const entry of entries) {
              // 视频完整进入视口开始播放,完全离开视口停止播放
              const video = entry.target;
              if (entry.isIntersecting) {
                  video.play();
              } else {
                  video.pause();
              }
          }
      }, {
          threshold: 1
      })

      videos.forEach(vdo => {
          ob.observe(vdo);
      })
  </script>
</html>

在这里插入图片描述

小结

在这里插入图片描述
Intersection Observer API是异步的,不随着目标元素的滚动同步触发。

注册的回调函数将在主线程中执行,因此执行速度应尽可能快,避免耗时操作。

兼容性:虽然大部分现代浏览器都支持Intersection Observer API,但在使用时仍需考虑兼容性问题。

当目标元素或其祖先元素使用了一些特殊的定位属性(如fixed、sticky或transform),或者元素本身被部分遮挡时,Intersection Observer API可能会产生不准确的观察结果,尽量避免在目标元素或其祖先元素上使用这些可能导致定位问题的属性。

综上所述,Intersection Observer API是一种强大的工具,用于优化网页的性能和用户体验。通过合理使用这个API,开发者可以更加高效地管理元素的可见性,实现各种交互效果。

Intersection Observer API 是一种基于观察者模式的浏览器 API,用于异步观察元素与浏览器视口的交集变化。当我们使用 IntersectionObserver 实例观测目标元素时,它会在元素进入或离开视口时向我们提供交叉信息的通知。这个 API 的主要用途是检测元素的可见性或两个元素的相对可见性变化,而不会影响网站的性能和用户体验。它可以帮助开发者实现一些业务需求和性能优化,同时简化处理交叉信息的代码细节,使开发者能够更专注于实现业务功能。如果您对 Intersection Observer API 还不熟悉,建议您学习一下,相信它会对您的前端开发工作带来很大的帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Intersection Observer API 详解](https://blog.csdn.net/qq_37788174/article/details/130599097)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [JS小知识,Intersection Observer API 使用指南](https://blog.csdn.net/Ed7zgeE9X/article/details/129075720)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值