判断元素是否在视口内

133 阅读1分钟
  1. 使用 getBoundingClientRect

通过 Element.getBoundingClientRect() 获取元素的位置信息,结合视口尺寸判断元素是否可见。

function isElementInViewport(el) {
  const rect = el.getBoundingClientRect();
  const windowHeight = window.innerHeight || document.documentElement.clientHeight;
  const windowWidth = window.innerWidth || document.documentElement.clientWidth;

  // 判断元素是否与视口有交集(部分或全部可见)
  return (
    rect.top < windowHeight &&
    rect.bottom > 0 &&
    rect.left < windowWidth &&
    rect.right > 0
  );
}

// 使用示例
const element = document.querySelector('#target');
window.addEventListener('scroll', () => {
  if (isElementInViewport(element)) {
    console.log('元素在视口内!');
  }
});

若要检测元素完全可见,条件改为:

rect.top >= 0 &&
rect.bottom <= windowHeight &&
rect.left >= 0 &&
rect.right <= windowWidth

Pasted_image_20250521141333.png

  1. 使用 Intersection Observer API

通过观察器异步检测元素与视口的交叉状态,性能更优且无需手动监听滚动事件。

// 创建观察器实例
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('元素进入视口!', entry.target);
      // 可选:停止观察已触发的元素
      // observer.unobserve(entry.target);
    } else {
      console.log('元素离开视口!');
    }
  });
}, {
  root: null,   // 默认为视口
  rootMargin: '0px', // 扩展/缩小检测区域
  threshold: 0.1    // 元素可见比例达到10%时触发
});

// 开始观察目标元素
const target = document.querySelector('#target');
observer.observe(target);

参数说明:

root: 根元素,默认为视口(null)。 rootMargin: 类似于 CSS 的 margin,扩展检测边界(如 "20px" 表示提前 20px 触发)。 threshold: 触发回调的可见比例阈值,支持数组(如 [0, 0.25, 0.5, 1])。

  1. 方法对比
方法优点缺点
getBoundingClientRect兼容性好(IE5+)需手动监听事件,频繁操作可能影响性能
IntersectionObserver高性能,支持复杂场景不兼容 IE11 及以下(需 polyfill)

资料:

Intersection_Observer_API