1️⃣ 作用

  • 高性能观察元素是否进入或离开视口(或指定容器)

  • 常用于:

    • 滚动触发动画(fadeIn、slideIn 等)
    • 图片懒加载
    • 无限滚动 / 瀑布流

2️⃣ 核心 API

1
2
3
4
const observer = new IntersectionObserver(callback, options);
observer.observe(targetElement); // 开始观察元素
observer.unobserve(targetElement); // 停止观察某个元素
observer.disconnect(); // 停止观察所有元素

3️⃣ callback 参数

1
(entries, observer) => { ... }
  • entries → 本次状态变化的元素数组,每个元素是 IntersectionObserverEntry 对象
  • observer → 当前 observer 对象本身

⚠️ entries 不包含视口里所有元素,只包含本次触发状态变化的元素


4️⃣ IntersectionObserverEntry 重要属性

属性 含义
target 当前被观察的元素
isIntersecting 元素是否进入可视区(true/false)
intersectionRatio 元素进入可视区域的比例(0~1)
boundingClientRect 元素自身边界
rootBounds 根元素边界(视口或指定容器)
intersectionRect 元素实际可见区域边界

5️⃣ options 参数

1
2
3
4
5
{
root: null, // 根元素,默认 viewport
rootMargin: '0px', // 类似 CSS margin,调整触发范围
threshold: 0 // 触发比例,可为 0~1 或数组
}
  • root → 观察的容器,null 表示 viewport

  • rootMargin → 扩展或收缩触发区域,例如提前 100px 执行动画:rootMargin: '0px 0px -100px 0px'

  • threshold → 元素进入视口的比例触发:

    • 0 → 只要一点点进入就触发
    • 1 → 完全进入才触发
    • [0, 0.5, 1] → 0%、50%、100% 都触发一次

6️⃣ 工作流程

  1. 创建 observer

  2. 注册要观察的元素 observe(element)

  3. 当元素状态变化(进入 / 离开 / 达到 threshold)时触发回调

  4. 回调里的 entries 数组包含 所有本次变化的元素

    • 即使只有一个元素,也用数组
    • 多个元素同时变化,数组里就包含这些元素
  5. 回调里处理逻辑(添加 class 播放动画、懒加载图片等)

  6. 可选停止观察:

    • unobserve(element) → 停止观察某个元素
    • disconnect() → 停止观察所有元素

7️⃣ 工程实践技巧

  1. 动画触发
1
2
3
4
5
6
entries.forEach(entry => {
if(entry.isIntersecting){
entry.target.classList.add('visible'); // 播放 CSS 动画
observer.unobserve(entry.target); // 播放一次就停止观察
}
});
  1. 多次触发
1
2
3
4
5
6
7
entries.forEach(entry => {
if(entry.isIntersecting){
entry.target.classList.add('active');
} else {
entry.target.classList.remove('active');
}
});
  1. 性能优化
  • 只观察必要元素
  • 尽量使用 transform / opacity 动画
  • 避免每帧 scroll 监听

8️⃣ 核心总结

  • IntersectionObserver = 高性能滚动可见性观察器
  • entries = 本次回调触发的元素数组(状态变化才入数组)
  • 支持批量触发 → 同一帧多个元素同时状态变化也只触发一次回调
  • 配合 CSS 动画或 JS 动画 → 滚动触发效果

如果你愿意,我可以帮你画一张 滚动触发 + entries 数组批量触发可视化图,把整个流程一眼看懂。

你希望我画吗?