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