浏览器的 5 种 Observer
介绍了监听网页元素的变化的5种观察者
对于一些不是由用户直接触发的事件, 比如元素从不可见到可见、元素大小的改变、元素的属性和子节点的修改等,这类事件如何监听呢?
浏览器提供了 5 种 Observer 来监听这些变动:MutationObserver、IntersectionObserver、PerformanceObserver、ResizeObserver、ReportingObserver。
IntersectionObserver
IntersectionObserver:监听一个元素从不可见到可见,从可见到不可见。
IntersectionObserver 可以监听一个元素和可视区域相交部分的比例,然后在可视比例达到某个阈值的时候触发回调。
<style>
#box1,
#box2 {
width: 100px;
height: 100px;
background: blue;
color: #fff;
position: relative;
}
#box1 {
top: 500px;
}
#box2 {
top: 800px;
}
</style>
<div id="box1">BOX111</div>
<div id="box2">BOX222</div>
<script>
const intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
console.info(entry.isIntersecting,entry.target,entry.intersectionRatio)
});
},{threshold:[0.5,1]} // 可见比例为0.5 和1触发回调
);
const box1 = document.getElementById('box1');
const box2 = document.getElementById('box2');
intersectionObserver.observe(box1);
intersectionObserver.observe(box2);
</script>
MutationObserver
MutationObserver 可以监听对元素的属性的修改、对它的子节点的增删改。
// Select the node that will be observed for mutations
const targetNode = document.getElementById("some-id");
// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };
// Callback function to execute when mutations are observed
const callback = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.type === "childList") {
console.log("A child node has been added or removed.");
} else if (mutation.type === "attributes") {
console.log(`The ${mutation.attributeName} attribute was modified.`);
}
}
};
// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
// Later, you can stop observing
observer.disconnect();
ResizeObserver
元素可以用 ResizeObserver 监听大小的改变,当 width、height 被修改时会触发回调。
<style>
#box {
width: 100px;
height: 100px;
background: blue;
}
</style>
<div id="box"></div>
<script>
const box = document.querySelector('#box');
setTimeout(() => {
box.style.width = '200px';
}, 2000);
const resizeObserver = new ResizeObserver(entries => {
console.log(entries)
})
resizeObserver.observe(box)
</script>
PerformanceObserver
PerformanceObserver()
构造函数使用给定的观察者 callback
生成一个新的 PerformanceObserver
对象。当通过 observe()
方法注册的 条目类型 的 性能条目事件 被记录下来时,调用该观察者回调。
<html>
<body>
<button onclick="measureClick()">Measure</button>
<img src="https://p9-passport.byteacctimg.com/img/user-avatar/4e9e751e2b32fb8afbbf559a296ccbf2~300x300.image" />
<script>
const performanceObserver = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
console.log(entry);// 上报
})
});
performanceObserver.observe({entryTypes: ['resource', 'mark', 'measure']});
performance.mark('registered-observer');
function measureClick() {
performance.measure('button clicked');
}
</script>
</body>
</html>
创建 PerformanceObserver 对象,监听 mark(时间点)、measure(时间段)、resource(资源加载耗时) 这三种记录时间的行为。
然后我们用 mark 记录了某个时间点,点击 button 的时候用 measure 记录了某个时间段的数据。
当这些记录行为发生的时候,希望能触发回调,在里面可以上报。
ReportingObserver
当浏览器运行到过时(deprecation)的 api 的时候,会在控制台打印一个过时的报告;浏览器还会在一些情况下对网页行为做一些干预(intervention),比如会把占用 cpu 太多的广告的 iframe 删掉。
![[image.png]]
![[image-1.png]]
浏览器提供了 ReportingObserver 的 api 用来监听这些报告的打印,我们可以拿到这些报告然后上传。
const options = {
types: ["deprecation"],
buffered: true,
};
const observer = new ReportingObserver((reports, observer) => {
reportBtn.onclick = () => displayReports(reports);
}, options);
observer.observe();
浏览器提供了这 5 种 Observer:
- IntersectionObserver:监听元素可见性变化,常用来做元素显示的数据采集、图片的懒加载
- MutationObserver:监听元素属性和子节点变化,比如可以用来做去不掉的水印
- ResizeObserver:监听元素大小变化
还有两个与元素无关的:
- PerformanceObserver:监听 performance 记录的行为,来上报数据
- ReportingObserver:监听过时的 api、浏览器的一些干预行为的报告,可以让我们更全面的了解网页 app 的运行情况