IntersectionObserver可视区监控

IntersectionObserver 是浏览器提供的一个原生 API,用于异步监听目标元素与其祖先元素或视口(viewport)之间的交叉状态(即“可见性”)变化。

简单说,它能告诉你:某个元素是否进入了浏览器可视区域,以及进入了多少。

在它出现之前,判断元素是否可见,通常要监听 scroll 事件,然后用 getBoundingClientRect() 手动计算位置。但这种方式有两大痛点:

性能差:scroll 事件触发极其频繁,频繁计算会导致页面卡顿。

代码复杂:需要手动处理节流、边界条件等。

IntersectionObserver 则把这一切交给浏览器底层去处理,异步、高效、不阻塞主线程,是性能最优的可见性监测方案。

// 1. 创建观察器实例
const observer = new IntersectionObserver((entries) => {
 //entries 回调函数接收一个数组,包含所有被观察元素的状态变化信息。每个 entry 包含 target(目标元素)、isIntersecting(是否交叉)、intersectionRatio(可见比例 0~1)等。
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('元素进入可视区域了!', entry.target)
      // 可以在这里做:懒加载图片、埋点上报、播放动画等
    }
  })
}, {
  // 配置项(可选)
  
  threshold: 0.5,   // 阈值,决定“可见多少比例时才触发回调”。可以是 0(刚露头)、0.5(半可见)、1(完全可见),也可以是数组 [0, 0.25, 0.5, 0.75, 1] 表示每个比例都触发。目标元素有50%可见时才触发回调
  rootMargin: '0px',  // 扩大或缩监视窗口边界,比如 '50px' 表示当元素距离视口边缘还有50px时就算“可见”。
  root: document.getElementById('content'); //默认是视口(viewport),也可以指定为某个容器元素,实现“元素在某个滚动容器内可见”的监听。
})

// 2. 指定要观察的目标元素
const target = document.querySelector('#myElement')
observer.observe(target)

// 3. 停止观察(可选)
// observer.unobserve(target)
// observer.disconnect()

实际应用场景

  1. 图片懒加载(最常见)
// javascript
const imgObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target
      img.src = img.dataset.src  // 替换真实图片地址
      imgObserver.unobserve(img) // 加载后停止观察
    }
  })
})
document.querySelectorAll('img[data-src]').forEach(img => imgObserver.observe(img))
  1. 无限滚动(下拉加载更多)
    当列表底部的“加载中”占位元素进入视口时,自动请求下一页数据。

  2. 埋点上报(曝光统计)
    商品卡片或广告位进入视口时,自动上报曝光数据,用于数据分析。

  3. 动画触发(滚动进入时播放)
    页面滚动到某个区块时,触发 CSS 动画或 JS 动画执行。

  4. 广告可见性监测
    检测广告是否真正被用户看到(而非只是加载了但没滚动到),用于结算依据。

重要注意事项
兼容性:现代浏览器(Chrome 51+、Firefox 55+、Safari 12.1+)都支持,但在 IE 中完全不支持,需要 polyfill。

回调触发时机:即使 threshold: 0,元素只有在首次进入或完全离开时才会触发回调。如果元素已经可见,初始状态不会触发,需要配合 getBoundingClientRect() 额外处理。

性能依然要注意:虽然比 scroll 事件好很多,但如果同时观察成千上万个元素,仍然可能消耗资源。建议通过 unobserve 及时释放不需要观察的元素。

rootMargin 的单位:支持 px 和 %,但 % 是相对于 root 尺寸的,使用时要注意。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容