IntersectionObserver 介绍
IntersectionObserver API 允许开发者异步监听目标元素与其祖先元素或视口(viewport)的交集变化。
- 目标元素: 被观察可见性的元素
- 根元素: 目标元素相对可见性的容器,默认为视口
- 相交: 当目标元素进入/离开根元素的可见区域时触发
核心用途
- 图片或内容的懒加载
- 无限滚动页面
- 广告曝光统计
- 动画触发
性能优化
减少初始加载资源
资源管理
按需加载资源
用户体验
更快的页面加载
IntersectionObserver 是一个现代的浏览器 API,用于异步监听目标元素与其祖先元素或视口(viewport)的交叉状态变化。它解决了传统滚动检测的性能问题,特别适用于实现懒加载、无限滚动、广告曝光统计等场景
观察器(Observer):监控一个或多个目标元素。
根元素(Root):默认是浏览器视口,也可指定为自定义容器(需是目标元素的祖先)。
交叉比例(Intersection Ratio):目标元素与根元素重叠部分占目标元素的比例(0.0~1.0)。
阈值(Threshold):触发回调的交叉比例临界点(如 [0, 0.25, 0.5, 1])。
// 1. 创建观察器
const observer = new IntersectionObserver(callback, options);
// 2. 观察目标元素
const target = document.querySelector('.box');
observer.observe(target);
// 3. 回调函数
const callback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("元素进入视口!");
}
});
};
// 4. 配置选项
const options = {
root: null, // 默认视口
rootMargin: '0px', // 扩展/缩小根元素的检测边界
threshold: 0.5 // 50%可见时触发
};
const observer = new IntersectionObserver(callback, options);
callback
(必需)entries
:IntersectionObserverEntry
对象数组,包含所有被观察元素的交叉信息
observer
:调用该回调的IntersectionObserver
实例
options
(可选)属性 | 类型 | 默认值 | 描述 |
---|---|---|---|
root |
Element | null |
用作视口的祖先元素(null 表示浏览器视口),必须是目标元素的祖先节点 |
rootMargin |
string | '0px' |
类似CSS margin语法("10px 20px 30px 40px"),可为负值,扩展/缩小检测区域 |
threshold |
number/Array | 0 |
触发回调的交叉比例阈值(如0.5 或[0, 0.25, 0.5, 1] ) |
方法 | 参数 | 描述 |
---|---|---|
observe(target) |
DOM元素 | 开始观察指定元素 |
unobserve(target) |
DOM元素 | 停止观察指定元素 |
disconnect() |
无 | 停止所有观察并关闭观察器 |
takeRecords() |
无 | 立即返回所有未处理的交叉记录 |
entries
数组中的 IntersectionObserverEntry
对象属性:
属性 | 类型 | 描述 |
---|---|---|
boundingClientRect |
DOMRect | 目标元素的边界矩形(相对于视口) |
intersectionRect |
DOMRect | 目标与根元素的交叉区域矩形 |
intersectionRatio |
number | 交叉区域占目标元素的比例(0.0~1.0) |
isIntersecting |
boolean | 目标元素是否与根元素相交(最常用属性) |
rootBounds |
DOMRect | 根元素的边界矩形 |
target |
Element | 被观察的目标元素 |
time |
number | 从观察器创建到交叉状态变化的时间戳(毫秒) |
异步执行:交叉检测由浏览器在空闲时执行,不阻塞主线程
批量处理:单次回调处理所有发生变化的元素(通过entries
数组)
精确阈值:可设置多个阈值点,在元素交叉比例达到每个阈值时触发回调
边界扩展:通过rootMargin
可扩展检测边界(如提前200px触发:"200px 0px"
)
自动计算:浏览器自动处理滚动容器、变换(transform)、缩放等复杂布局的计算
注意:当不再需要观察时,务必调用
disconnect()
或unobserve()
释放资源
回调函数中的 entry
包含以下关键属性:
entry.boundingClientRect; // 目标元素的矩形信息
entry.intersectionRatio; // 当前交叉比例(0.0~1.0)
entry.isIntersecting; // 是否交叉(最常用!)
entry.intersectionRect; // 交叉区域的矩形信息
entry.target; // 目标元素本身
entry.time; // 从观察器创建到交叉的时间戳
每个属性提供元素交叉状态的关键几何信息和时间数据,用于精确控制交互行为:
boundingClientRect
作用:获取目标元素相对于浏览器视口的位置和尺寸
数据结构:DOMRect 对象包含:
{
x: 100, // 元素左边界到视口左边的距离
y: 200, // 元素上边界到视口顶部的距离
width: 300, // 元素宽度(含padding/border)
height: 150, // 元素高度
top: 200, // = y
right: 400, // 元素右边界位置(x + width)
bottom: 350 // 元素下边界位置(y + height)
}
典型用途:计算元素在屏幕中的精确位置(如吸顶导航栏的触发点)
intersectionRatio
作用:量化目标元素与根元素重叠的程度
数值范围:0.0(完全不可见)→ 1.0(完全可见)
计算方式:
重叠区域面积 ÷ 目标元素总面积
典型用途:
实现淡入动画:element.style.opacity = entry.intersectionRatio
视频音量控制:音量随可见比例变化
isIntersecting
作用:快速判断是否发生交叉(最常用属性)
特性:
true:目标元素至少1像素进入根元素范围
false:目标元素完全离开根元素范围
典型用途:
if (entry.isIntersecting) {
// 执行懒加载/触发动画
}
intersectionRect
作用:获取实际重叠区域的几何信息
数据结构:同boundingClientRect的DOMRect
关键值:
{
width: 120, // 重叠区域宽度
height: 80 // 重叠区域高度
}
典型用途:
计算广告的有效曝光面积(如要求50%可见才计费)
精确控制动画触发条件(例如元素中心点可见时才触发)
target
作用:直接引用被观察的DOM元素
典型用途:
entries.forEach(entry => {
// 直接操作目标元素
entry.target.classList.add('active')
})
time
作用:记录从观察器创建到交叉事件发生的时间差(毫秒)
典型用途:
性能监控:统计元素进入视口的耗时
曝光时长计算:结合isIntersecting
变化计算停留时间
const start = Date.now();
const observer = new IntersectionObserver(entries => {
const loadTime = entry.time;
console.log(`元素${entry.target.id}在${loadTime}ms后进入视口`);
});
属性 | 解决的关键问题 | 实际应用场景 |
---|---|---|
isIntersecting |
快速判断元素是否可见 | 懒加载/动画开关 |
intersectionRatio |
量化可见程度 | 渐进式动画/精准曝光统计 |
boundingClientRect |
获取元素实时位置 | 吸顶导航/元素位置跟踪 |
intersectionRect |
计算实际可见区域 | 广告有效曝光判定 |
target |
直接操作目标元素 | 动态修改样式/绑定事件 |
time |
测量交叉事件发生的时机 | 性能监控/用户行为分析 |
const lazyLoad = (img) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
img.src = img.dataset.src; // 替换 data-src 为真实 URL
observer.unobserve(img);
}
});
});
observer.observe(img);
};
observer.observe(document.querySelector('.footer-loader'));
// 当加载器进入视口时,请求新数据追加到列表
.hidden { opacity: 0; transform: translateY(20px); }
.animate { transition: 1s; opacity: 1; transform: none; }
let timer;
observer.observe(adElement, { threshold: 0.5 });
// 在回调中通过 setTimeout 记录曝光
传统滚动监听 | IntersectionObserver |
---|---|
频繁触发 scroll 事件,性能开销大 | 异步处理,无性能负担 |
需手动计算元素位置 | 浏览器自动计算交叉状态 |
兼容性较好但代码复杂 | 现代浏览器原生支持(IE 需 polyfill) |
及时断开观察
使用 unobserve()
或 disconnect()
避免内存泄漏。
observer.unobserve(target); // 停止观察单个元素
observer.disconnect(); // 停止所有观察
阈值数组触发多次
设置 threshold: [0, 0.5, 1]
时,元素经过 0%、50%、100% 会触发三次回调。
兼容性
支持所有现代浏览器(Chrome 51+、Firefox 55+、Safari 12.1+)。
IE 需使用 polyfill。
IntersectionObserver 是高性能元素可见性检测的终极方案,通过异步机制和精细的交叉比例控制,完美替代了易导致性能问题的滚动监听逻辑。掌握它能大幅优化用户体验与页面性能!
IntersectionObserver 懒加载演示
IntersectionObserver API 演示
高效实现图片懒加载,提升网页性能
IntersectionObserver 介绍
IntersectionObserver API 允许开发者异步监听目标元素与其祖先元素或视口(viewport)的交集变化。
- 目标元素: 被观察可见性的元素
- 根元素: 目标元素相对可见性的容器,默认为视口
- 相交: 当目标元素进入/离开根元素的可见区域时触发
核心用途
- 图片或内容的懒加载
- 无限滚动页面
- 广告曝光统计
- 动画触发
性能优化
减少初始加载资源
资源管理
按需加载资源
用户体验
更快的页面加载
观察器配置
0%
50%
100%
-100px
0px
100px
事件日志