IntersectionObserver
IntersectionObserver 接口(从属于 Intersection Observer API)提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)。
当一个 IntersectionObserver 对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。
1. 用法
通过new关键字调用IntersectionObserver()构造函数创建一个IntersectionObserver对象实例,构造函数接收两个参数callback和options
const root = document.querySelector('.root')
const imgList = document.querySelectorAll('img')
const option = {
root: root,
rootMargin: 0,
thresholds: 1,
}
// 定义相交监视器
var observer = new IntersectionObserver(entries => {
console.log(entries); //一个IntersectionObserverEntry对象实例数组,包含所有被监视的IntersectionObserverEntry对象
entries.forEach(entrie => {
console.log(entrie.time); // 发生变化的时间
console.log(entrie.rootBounds); // 根元素的矩形区域的信息
console.log(entrie.boundingClientRect); // 目标元素的矩形区域的信息
console.log(entrie.intersectionRect); // 目标元素与视口(或根元素)的交叉区域的信息
console.log(entrie.intersectionRatio); // 目标元素与视口(或根元素)的相交比例
console.log(entrie.target); // 被监视的目标元素
})
}, option);
// 开始监视某个目标元素
observer.observe(target);
// 停止监视某个目标元素
observer.unobserve(target);
// 关闭监视器
observer.disconnect();
2. IntersectionObserver callback
callback是添加监听后,当监视的目标元素的可见比例超过指定阈值时,即目标元素到达可视区域时触发该回调函函数。该回调函数接受两个参数:
- entries:
IntersectionObserverEntry对象实例数组,包含所有被监视的IntersectionObserverEntry对象,描述所有目标元素与root的交叉状态。 - observer:被调用的
IntersectionObserver实例
2.1. IntersectionObserverEntry 介绍
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
2.2. IntersectionObserver Entry 图解
- time:发生相交到相应的时间,毫秒。
- rootBounds:根元素矩形区域的信息,如果没有设置根元素则返回null,图中蓝色部分区域。
- boundingClientRect:目标元素的矩形区域的信息,图中黑色边框的区域。
- intersectionRect:目标元素与视口(或根元素)的交叉区域的信息,图中蓝色方块和粉红色方块相交的区域。
- isIntersecting:目标元素与根元素是否相交
- intersectionRatio:目标元素与视口(或根元素)的相交比例。
- target:目标元素,图中黑色边框的部分。
3. IntersectionObserver options
options是一个对象,用来配置参数,也可以不填。共有三个属性,具体如下:
| 属性 | 说明 |
|---|---|
| root | 所监听对象的具体祖先元素。如果未传入值或值为null,则默认使用顶级文档的视窗(一般为html)。 |
| rootMargin | 计算交叉时添加到根(root)边界盒bounding box的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。所有的偏移量均可用像素(px)或百分比(%)来表达, 默认值为”0px 0px 0px 0px”。 |
| threshold | 一个包含阈值的列表, 按升序排列, 列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发callback。默认值为0。 |
options图解介绍
- root:设置监视器的根节点,不传则默认为视口。
- rootMargin: 类似于 CSS 的 margin 属性。用来缩小或扩大 rootBounds,从而影响相交的触发。如下图,当我们把 rootMargin 设置为[“-5px”, “-8px”, “-10px”, “-8px”]时,可视区域缩小为黑色框区域,目标元素只有进入黑色框区域才会触发回调函数。
- threshold:属性决定相交比例为多少时,触发回调函数。取值为 0 ~ 1,或者 0 ~ 1的数组。 如下图,当我们把 threshold 设置为 [0, 0.25, 0.5, 0.75, 1],绿色方块分别在 0%,25%,50%,75%,100% 可见时,触发回调函数。
4.方法
介绍了这么多配置项及参数,差点忘了最重要的,IntersectionObserver有哪些方法? 如果要监听某些元素,则必须要对该元素执行一下observe
| 方法 | 说明 |
|---|---|
| observe() | 开始监听一个目标元素 |
| unobserve() | 停止监听特定目标元素 |
| takeRecords() | 返回所有观察目标的IntersectionObserverEntry对象数组 |
| disconnect() | 使IntersectionObserver对象停止全部监听工作 |
5.应用
① 图片懒加载
img标签使用默认图片,自定义属性data-resource-url存储真实图片地址img标签进入可视区域时替换真实图片地址
<!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">
<link rel="stylesheet" href="./index.css">
<title>Document</title>
</head>
<body>
<div class="root">
<img src="./img/default_img.jpg" alt="" data-resource-url="./img/Icon.png">
<img src="./img/default_img.jpg" alt="" data-resource-url="./img/unko-anime.gif">
<img src="./img/default_img.jpg" alt="" data-resource-url="./img/喇叭.png">
<img src="./img/default_img.jpg" alt="" data-resource-url="./img/喵喵.jpg">
<img src="./img/default_img.jpg" alt="" data-resource-url="./img/带刀剑士.png">
</div>
<script src="./index.js"></script>
</body>
</html>
* {
margin: 0;
padding: 0;
}
body {
position: relative;
width: 100vw;
height: 100vh;
}
.root {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 300px;
border: 2px solid slategray;
overflow-y: auto;
}
.root img {
display: block;
margin: 0 auto;
width: 100%;
height: 210px;
border: 1px solid rgb(94, 100, 102);
}
const root = document.querySelector('.root')
const imgList = document.querySelectorAll('img')
const observerOption = {
root: root,
}
//创建监听观察者实例
const observer = new IntersectionObserver((entries) => {
console.log(entries);
//entries: 是监听所有IntersectionObserverEntry的集合
entries.forEach((item) => {
// isIntersecting是一个Boolean值,判断目标元素当前是否可见
if (item.isIntersecting) {
// 进入可视区域替换真实图片地址(定时器延迟加载好观察效果)
setTimeout(() => {
item.target.src = item.target.dataset.resourceUrl
},1000)
// 图片加载后即停止监听该元素
observer.unobserve(item.target)
}
})
}, observerOption)
//observe遍历监听所有img节点
imgList.forEach(img => observer.observe(img))
6.参考链接
MDN: IntersectionObserver
MDN: IntersectionObserverEntry
超好用的API之IntersectionObserver - 掘金 (juejin.cn)
深入理解 Intersection Observer - 掘金 (juejin.cn)

