创建
- 创建一个 IntersectionObserver 对象,并传入相应参数和回调用函数,该回调函数将会在目标(
target
)元素和根(root
)元素的交集大小超过阈值(threshold
)规定的大小时候被执行。
js
const ob = new IntersectionObserver(callback, option)
- callback: 交叉改变后运行: 交叉/不交叉 => 不交叉/交叉
- option: 配置项目
root
: 指定根(root
)元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null
,则默认为浏览器视窗。rootMargin
: 根(root
)元素的外边距。类似于 CSS 中的 margin 属性,比如 "10px 20px 30px 40px" (top, right, bottom, left)。如果有指定 root 参数,则 rootMargin 也可以使用百分比来取值。该属性值是用作 root 元素和 target 发生交集时候的计算交集的区域范围,使用该属性可以控制 root 元素每一边的收缩
或者扩张
。默认值为 0。threshold
: 阈值!可以是单一的 number 也可以是 number 数组,target 元素和 root 元素相交程度达到该值的时候 IntersectionObserver 注册的回调函数将会被执行。如果你只是想要探测当 target 元素的在 root 元素中的可见性超过 50%的时候,你可以指定该属性值为 0.5。如果你想要 target 元素在 root 元素的可见程度每多 25%就执行一次回调,那么你可以指定一个数组[0, 0.25, 0.5, 0.75, 1]。默认值是 0(意味着只要有一个 target 像素出现在 root 元素中,回调函数将会被执行)。该值为 1.0 含义是当 target 完全出现在 root 元素中时候 回调才会被执行。
- IntersectionObserver Entry
IntersectionObserverEntry 对象提供了目标元素与跟元素相交的详细信息。他有如下几个属性。
typescript
interface IntersectionObserverEntry {
readonly attribute DOMHighResTimeStamp time;
readonly attribute DOMRectReadOnly? rootBounds;
readonly attribute DOMRectReadOnly boundingClientRect;
readonly attribute DOMRectReadOnly intersectionRect;
readonly attribute boolean isIntersecting;
readonly attribute double intersectionRatio;
readonly attribute Element target;
};

- time:发生相交到相应的时间,毫秒。
- rootBounds:根元素矩形区域的信息,如果没有设置根元素则返回 null,图中蓝色部分区域。
- boundingClientRect:目标元素的矩形区域的信息,图中黑色边框的区域。
- intersectionRect:目标元素与视口(或根元素)的交叉区域的信息,图中蓝色方块和粉红色方块相交的区域。
- isIntersecting:目标元素与根元素是否相交(满足预设的阈值条件)
- intersectionRatio:目标元素与视口(或根元素)的相交比例。
- target:目标元素,图中黑色边框的部分。
js
var observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
console.log(entry.time) // 发生变化的时间
console.log(entry.rootBounds) // 根元素的矩形区域的信息
console.log(entry.boundingClientRect) // 目标元素的矩形区域的信息
console.log(entry.isIntersection) // 目标元素与视口(或根元素)是否相交(满足预设的阈值条件)
console.log(entry.intersectionRect) // 目标元素与视口(或根元素)的交叉区域的信息
console.log(entry.intersectionRatio) // 目标元素与视口(或根元素)的相交比例
console.log(entry.target) // 被观察的目标元素
}
}, {})
// 开始观察某个目标元素
observer.observe(target)
// 停止观察某个目标元素
observer.unobserve(target)
// 关闭监视器
observer.disconnect()
// 获取所有 IntersectionObserver 观察的 targets
observer.takeRecords()
请留意,你注册的回调函数将会在主线程中被执行。所以该函数执行速度要尽可能的快。如果有一些耗时的操作需要执行,建议使用 Window.requestIdleCallback()
方法。
所有区域均被 Intersection Observer API 当做一个矩形看待。如果元素是不规则的图形也将会被看成一个包含元素所有区域的最小矩形,相似的,如果元素发生的交集部分不是一个矩形,那么也会被看作是一个包含他所有交集区域的最小矩形。
这个有助于理解 IntersectionObserverEntry 的属性,IntersectionObserverEntry 用于描述 target
和 root
的交集。
应用
图片懒加载
html
<!-- html -->
<img src='default.png' data-src="xxxxx" />
<img src='default.png' data-src="xxxxx" />
<img src='default.png' data-src="xxxxx" />
<img src='default.png' data-src="xxxxx" />
js
// js
const ob = new IntersectionObserver(
entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
ob.unobserve(img);
}
}
},
{
root: null,
rootMargin: 0,
threshold: 0
}
);
const imgs = document.querySelectorAll('img[data-src]')
imgs.forEach(img => {
ob.observe(img)
})
下拉加载更多
方式:在dom元素之下存在一个加载动画。当加载动画出现在视口中,继续添加dom元素
html
<div>
// 省略其他dom元素...
</div>
<loading></loading>
js
const ob = new IntersectionObserver(
entries => {
if (entries[0].isIntersecting) {
// ...添加doms
}
},
{
root: null,
rootMargin: '0',
threshold: 0
}
);
const loading = document.querySelector('.loading');
ob.observe(loading);