Introduction
IntersectionObserver provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or the top-level document viewport.
IntersectionObserver receives two parameters, callback and options. options are optional and have default values.
const observer = new IntersectionObserver(callback[, options]);
basic use
<div class="viewableArea">
指定的可视区域
<div class="target">被监听的目标元素</div>
内容很多,都多到出现滚动条了。内容很多,都多到出现滚动条了。内容很多,都多到......
</div>
const specifiedViewableArea = document.getElementsByClassName('viewableArea')[0];
const target = document.getElementsByClassName('target')[0];
const options = {
// 指定可视区域
root: specifiedViewableArea,
// 给可视区域添加”虚拟“外边距
rootMargin: '0px',
// 当目标元素与指定可视区发生交叉,且目标元素出现在可视区的部分占目标元素的比例是0.33时,触发callback的调用。
threshold: 0.33,
};
const callback = (entries: IntersectionObserverEntry[], observer?: IntersectionObserver) => {
entries.forEach((entry) => {
console.log('entry:', entry);
// todo 根据entry里的信息判断是否要你想做的事情
if (entry.isIntersecting) {
console.log('intersecting');
} else {
console.log('not intersecting');
}
});
};
// 创建并返回一个IntersectionObserver交叉观察者实例,并传入 callback回到函数 和 options配置项。
// callback 在什么时候调用? ----> 当目标元素与可视区域交叉的部分占目标元素的比例达到options设置的阈值threshold时调用。
// 两个时机:当目标元素进入可视区时、当目标元素离开可视区时。
const observer = new IntersectionObserver(callback, options);
// 开始观察目标元素
observer.observe(target);
example
Example 1
const options = {
root: specifiedViewableArea,
rootMargin: '0px',
// threshold可以是一个number,值在0~1之间。
// 这里,当目标元素的只有三分之一出现在可视区时,触发callback
threshold: 0.33,
};
Example 2
const options = {
root: specifiedViewableArea,
rootMargin: '0px',
// threshold 可以是一个升序的数组。
// 当目标元素在进入或离开可视区域时,交叉区域的阈值满足数组中任意一个值,都会触发callback。
threshold: [0.3, 0.7],
};
state 1:
state 2:
state 3:
Example 3
const options = {
root: specifiedViewableArea,
// 添加虚拟边界作为可视区的一部分,这也作为可视区和目标元素交叉的一部分。
rootMargin: '50px',
threshold: 0.25,
};
Related API instructions
IntersectionObserver
interface IntersectionObserver {
// 要监听的可视区域,默认是顶级文档的视窗。
readonly root: Element | Document | null;
// 计算可视区交叉时添加到根(root)边界盒bounding box的矩形偏移量,默认值为"0px 0px 0px 0px"。
// 当计算交叉时,会把它看作是指定可视区的一部分。
readonly rootMargin: string;
// 一个按升序排列的阈值列表,当目标元素在进入或离开可视区域时,交叉区域的阈值满足数组中任意一个值,都会触发callback。默认值为0。
readonly thresholds: ReadonlyArray<number>;
// 停止所有监听。
disconnect(): void;
// 开始监听目标元素。
observe(target: Element): void;
// 返回所有被观察目标的记录。
takeRecords(): IntersectionObserverEntry[];
// 取消监听目标元素。
unobserve(target: Element): void;
}
IntersectionObserverEntry
This interface records the information when the target element intersects with the specified visible area at a specific transition moment.
interface IntersectionObserverEntry {
// 返回目标元素的边界信息,包括left、right、top、buttom、width、height、x、y。
readonly boundingClientRect: DOMRectReadOnly;
// 返回目标元素出现在可视区的比例。
readonly intersectionRatio: number;
// 返回目标元素和可视区的相交区域的边界信息。
readonly intersectionRect: DOMRectReadOnly;
// 当目标元素出现在可视区时返回true。当目标元素从可视区消失时返回false。这两种情况均触发callback的调用。
readonly isIntersecting: boolean;
// 可视区的边界信息。
readonly rootBounds: DOMRectReadOnly | null;
// 目标元素。
readonly target: Element;
// 从开始监听到发生交叉的时间戳。
readonly time: DOMHighResTimeStamp;
}
application
When the page scrolls, perform animation effects
const observer = new IntersectionObserver(
(entries: IntersectionObserverEntry[]) => {
if (entries[0].intersectionRatio <= 0.33) {
// 动画相关代码...
}
},
{
root: specifiedViewableArea,
threshold: 0.33
}
);
observer.observe(target);
Lazy loading resources
For example, lazy loading of image resources.
const observer = new IntersectionObserver(
(entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 加载图片的相关代码... 给img的src属性赋值
// 取消对当前元素的监听
observer.unobserve(entry.target);
}
});
}
);
// 观察所有要加载图片的元素
const imgList = document.querySelectorAll('img');
imgList.forEach((img) => observer.observe(img));
Buried exposure
When the target element completely appears in the specified visible area, perform buried point exposure.
const observer = new IntersectionObserver(
(entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
// 目标元素完全暴露在可视区域中
if (entry.intersectionRatio === 1) {
//埋点曝光相关代码...
// 取消对当前元素的监听
observer.unobserve(entry.target);
}
});
},
{
root: null,
threshold: 1,
}
);
// 观察要进行埋点曝光的元素
observer.observe(target)
reference study
MDN document: https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
Nugget article: https://juejin.cn/post/6844903874302574599