html5的Intersection Observer怎么用_html4监听元素可见性吗【教程】

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),因为后者在完全离开时可能为 0isIntersecting 已为 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(),否则内存泄漏风险真实存在。