Skip to content

怎么判断元素进入了可视区域? ​

优先用 IntersectionObserver。它异步告诉你目标元素和视口(或某个滚动容器)相交了多少,不用在滚动事件里不断读布局。

原理 ​

js
const observer = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      // 进入可视区域
    }
  }
}, { threshold: 0.5 })
observer.observe(element)

threshold 是相交比例。root 不传时相对视口,传一个祖先时相对那个滚动容器。rootMargin 可以提前或推迟触发,用来做预加载。

组件或节点不再需要观察时调用 unobserve 或 disconnect,否则回调还握着旧节点。

老环境可以比较 getBoundingClientRect() 和视口宽高。这个读取会触发布局,不要绑在未经节流的滚动事件上。

追问 ​

图片懒加载还要自己写吗?

普通图片用 loading="lazy"。需要进入视口才渲染一整块组件、或要提前几百像素加载时,再用观察器。首屏最大的图不要懒加载,那会推迟 LCP。

和滚动监听比呢?

滚动回调在主线程上,读几何信息容易造成强制同步布局。观察器由浏览器在合适的时机计算相交,适合列表哨兵、曝光埋点、懒加载。

易错点 ​

  • 元素在 display: none 的祖先里,观察器不会认为它可见。
  • 滚动容器不是视口时,忘了设 root,回调的相交对象是错的。
  • 哨兵一开始就完全可见,会立刻把后续页全部请求完。见 无限列表。

相关 ​