一、IntersectionObserver的介绍
- 基本介绍
传统的实现方法是,监听到scroll事件后,以及计算视口高度,再判断是否在视口之内。这种方法的缺点是,由于scroll事件密集发生,计算量很大,容易造成性能问题。
目前有一个新的 IntersectionObserver API,可以自动"观察"元素是否可见,Chrome 51+ 已经支持。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。
- IntersectionObserver 中的api
var io = new IntersectionObserver(callback, option);
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
上面代码中,IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。
构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节
二、React中的使用举例(滚动到一定程度固定头部)
-
运用实例
-
初始化
dom是所监听节点,使用useRef保存observer实例,方便在卸载组件时清除监听。通过isFixed变量通知dom节点是否固定
const observer = useRef(); //监听保存
const initObserver = () => {
const dom = document.getElementById("fundsName");
const config = {
rootMargin: "0px",
threshold: 0,
};
//监听dom是否在视口内
observer.current = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsFixed(true);
} else {
setIsFixed(false);
}
});
}, config);
observer.current.observe(dom);
};
- 组件卸载时清除监听
监听滚动 --监听第一个id过后固定
// 使用disconnect将保存的Observer实例中监听的函数全部解散
const resetObserver = () => {
observer.current.disconnect();
};
useEffect(() => {
initObserver();
return () => {
resetObserver();
setIsFixed(false);
};
}, []);
总结:通过IntersectionObserver监听dom节点是否在视口中,可以避免dom元素过多从而计算量很大,导致性能问题,也可以简化代码量。此方法也可用于图片懒加载等场景。下方代码是懒加载的用例代码,可供参考。
const imgs = document.querySelectorAll('img[data-src]')
const config = {
rootMargin: '0px',
threshold: 0
}
let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let img = entry.target
let src = img.dataset.src
if (src) {
img.src = src
img.removeAttribute('data-src')
}
// 解除观察
self.unobserve(entry.target)
}
})
}, config)
imgs.forEach((image) => {
observer.observe(image)
})