Intersection Observer 是 HTML5 原生 API,用于高效监听元素可见性;相比 HTML4 依赖 scroll + getBoundingClientRect 轮询的低效方案,它由浏览器异步触发、不阻塞主线程,支持阈值、根容器、进出视口等精细控制。

Intersection Observer 是什么,为什么不用 HTML4 的方案
HTML4 没有原生监听元素可见性的机制,所谓“HTML4 监听”本质上是靠 window.onscroll + getBoundingClientRect() 轮询模拟,性能差、代码冗长、容易漏掉首屏外动态插入的元素。Intersection Observer 是 HTML5 原生 API,由浏览器底层异步触发,不阻塞主线程,支持监听进入/离开视口、部分可见、阈值控制等,是当前唯一推荐方案。
基础用法:创建 observer 并监听目标元素
核心是实例化 IntersectionObserver,传入回调函数和可选配置,再调用 observe() 方法绑定 DOM 元素。注意:observer 不会自动监听子元素,每个目标需单独调用 observe()。
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('元素进入视口:', entry.target);
// 可在此处加载图片、启动动画、上报埋点
}
});
}, {
threshold: 0.1, // 元素 10% 进入视口时触发
rootMargin: '0px' // 等价于默认值,可设 '50px' 扩展检测区域
});
// 监听所有 class="lazy" 的元素
document.querySelectorAll('.lazy').forEach(el => observer.observe(el));
常见错误:callback 不触发或只触发一次
这是最常遇到的问题,原因集中在三类:
-
root配置错误:默认root: null表示根视口;若设了root: document.querySelector('#container'),但该容器未设置overflow: hidden/scroll/auto,则无法作为滚动上下文,observer 失效 - 目标元素未插入 DOM 或已被移除:observer 不会报错,但不会触发回调;建议在
observe()前确认el.isConnected === true - 未处理
isIntersecting === false场景:比如想实现“进入时加载、离开时卸载”,必须显式判断entry.isIntersecting,不能只写if (entry.intersectionRatio > 0),因为后者在完全离开时可能为0但isIntersecting已为false
性能与兼容性要点
Intersection Observer 在 Chrome 51+、Firefox 55+、Safari 12.1+、Edge 79+ 原生支持。iOS Safari 12.2+ 支持,但 iOS 12.0–12.1 有严重 bug(isIntersecting 始终为 false)。如需兼容老版本,可用 官方 polyfill,但注意 polyfill 本质还是 scroll + getBoundingClientRect,无法避免性能损耗。
立即学习“前端免费学习笔记(深入)”;
实际项目中,更关键的不是兼容性,而是别滥用:不要给上百个元素都挂 observer;对列表项,优先用「节流 + 虚拟滚动」;对单页应用路由切换后的元素,记得在组件销毁时调用 unobserve() 或 disconnect(),否则内存泄漏风险真实存在。










