IntersectionObserver,元素是否在视口内
传统方式
监听 scroll
事件,调用指定元素 getBoundingClientRect
方法,再判断元素是否在视口内;如果是嵌套滚动,则需要多级监听,多级判断,计算量很大,可能影响性能。
(function () {
const target = document.querySelector('.target');
const tip = document.querySelector('.tip');
let el = target;
while (el.parentNode) {
el.parentNode.addEventListener('scroll', scroll);
el = el.parentNode;
}
// 滚动事件
function scroll() {
tip.innerHTML = isVisible(target) ? '出现' : '隐藏';
}
// 元素是否可见
function isVisible(target) {
let el = target;
while (el) {
if (!inView(el)) return false;
el = el.parentElement;
}
return inView(target, target.parentElement.getBoundingClientRect());
}
// 元素是否在指定视口之内,只作了y轴判断
function inView(target, view = { top: 0, bottom: innerHeight }) {
const { top, bottom } = target.getBoundingClientRect();
return (
(top >= view.top && top <= view.bottom) ||
(bottom >= view.top && bottom <= view.bottom) ||
(top <= view.top && bottom >= view.top) ||
(bottom <= view.top && top >= view.top)
);
}
window.addEventListener('load', scroll);
})(window);
IntersectionObserver
提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。
方法
const observe = new IntersectionObserver(callback[, options]);
IntersectionObserver
接收两个参数,一个监听到变化时触发的回调函数 callback
,另一个配置对象 options
。
const target = document.querySelector(selector);
observe.observe(target); // 添加观察元素
observe.unobserve(target); // 移出观察元素
observe.disconnect(); // 关闭观察对象
callback 参数
callback
一般触发两次(目标元素进入视口,目标元素离开视口),有两个参数
entries
是一个IntersectionObserverEntry
对象的数组;observer
当前观察器的实例;
IntersectionObserverEntry
属性有很多,其中 isIntersecting
是一个 boolean
值,表示目标是否是视口范围内。
完整代码
const target = document.querySelector('.target');
const tip = document.querySelector('.tip');
const observe = new IntersectionObserver(entries => {
for (const entry of entries) {
tip.innerHTML = entry.isIntersecting ? '展示' : '隐藏';
}
});
observe.observe(target);
以上代码完全可以实现传统方式判断目标是否进入视口功能,兼容性方面IE浏览器全军覆没。