- 使用 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
- 使用 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])。
- 方法对比
方法 | 优点 | 缺点 |
---|---|---|
getBoundingClientRect | 兼容性好(IE5+) | 需手动监听事件,频繁操作可能影响性能 |
IntersectionObserver | 高性能,支持复杂场景 | 不兼容 IE11 及以下(需 polyfill) |
资料: