浏览器【详解】内置Observer(共五种,用于前端监控、图片懒加载、无限滚动、响应式布局、生成安全报告等)
通用语法
浏览器的内置Observer都需要通过 new 来创建实例 ob (自定义名称)
- 开始/继续监听 ob.observe(targetNode, config)
- targetNode 目标元素
- config 配置
- 暂停监听 ob.disconnect()
- 停止监听 ob.unobserve(targetNode)
MutationObserver
监听DOM 元素的变化(如节点增删、属性修改、文本内容变化等)
可用于延迟批量处理变化(避免频繁触发回调),提升性能。
// 选择目标节点
const targetNode = document.getElementById('target');// 配置观察选项
const config = {attributes: true, // 监听属性变化childList: true, // 监听子节点增删subtree: true // 监听所有后代节点
};// 回调函数:变化发生时执行
const callback = (mutationsList) => {for (const mutation of mutationsList) {if (mutation.type === 'childList') {console.log('子节点发生变化');} else if (mutation.type === 'attributes') {console.log(`属性 ${mutation.attributeName} 发生变化`);}}
};// 创建观察者实例
const observer = new MutationObserver(callback);// 开始观察目标节点
observer.observe(targetNode, config);// 停止观察(必要时)
// observer.disconnect();
交叉观察器 IntersectionObserver
监测目标元素与视口或祖先元素的交叉状态(如元素进入 / 离开视口),常用于懒加载、滚动动画等场景。
- 高效检测元素可见性,避免频繁触发scroll事件导致的性能问题。
- 支持配置交叉区域的阈值(如元素可见 50% 时触发)。
// 创建观察器
let ob = new IntersectionObserver(callback, option);
- 在元素进入视口和离开视口时,都会触发回调函数 callback
- callback 的参数是由 相交观察器条目 构成的数组,数组的数量由被观察对象的数量决定。
观察多个对象
ob.observe(elementA);
ob.observe(elementB);
相交观察器条目
共六个属性
- time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
- target:被观察的目标元素,是一个 DOM 节点对象
- rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
- boundingClientRect:目标元素的矩形区域的信息
- intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
- intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
配置选项
- threshold 触发的阈值,默认值为 [0] ,即元素一出现即触发
threshold: 0.1 // 元素可见10%时触发
threshold: [0.5,1] // 元素可见50% 和 100% 时都触发
- root 指定目标元素所在的容器节点(即根元素),容器元素必须是目标元素的祖先节点。
- rootMargin 定义根元素的margin,用来扩展或缩小rootBounds这个矩形的大小,从而影响intersectionRect交叉区域的大小。它使用CSS的定义方法,比如10px 20px 30px 40px,表示 top、right、bottom 和 left 四个方向的值。
注意事项
- IntersectionObserver 是异步的,不随着目标元素的滚动同步触发。
- IntersectionObserver 的优先级非常低,只在其他任务执行完,浏览器有了空闲才会执行。
实战范例 – 图片懒加载
// 目标元素(如图片)
const target = document.querySelector('.lazy-image');// 配置选项
const options = {root: null, // 以视口为参考rootMargin: '0px', // 扩展/收缩参考区域threshold: 0.1 // 元素可见10%时触发
};// 回调函数:交叉状态变化时执行
const callback = (entries) => {entries.forEach(entry => {if (entry.isIntersecting) {// 元素进入视口,加载图片entry.target.src = entry.target.dataset.src;// 停止观察已加载的元素observer.unobserve(entry.target);}});
};// 创建观察者实例
const observer = new IntersectionObserver(callback, options);// 开始观察目标元素
observer.observe(target);
或
function query(selector) {return Array.from(document.querySelectorAll(selector));
}var observer = new IntersectionObserver(function(changes) {changes.forEach(function(change) {var container = change.target;var content = container.querySelector('template').content;container.appendChild(content);observer.unobserve(container);});}
);query('.lazy-loaded').forEach(function (item) {observer.observe(item);
});
实战范例 – 无限滚动
var intersectionObserver = new IntersectionObserver(function (entries) {// 如果不可见,就返回if (entries[0].intersectionRatio <= 0) return;loadItems(10);console.log('Loaded new items');});// 开始观察
intersectionObserver.observe(document.querySelector('.scrollerFooter')
);
无限滚动时,最好在页面底部有一个页尾栏(又称sentinels)。一旦页尾栏可见,就表示用户到达了页面底部,从而加载新的条目放在页尾栏前面。这样做的好处是,不需要再一次调用observe()方法,现有的IntersectionObserver可以保持使用。
ResizeObserver
监听元素尺寸变化(如宽度、高度改变),适用于响应式布局、动态调整 UI 等场景。
// 目标元素
const target = document.querySelector('.resizable-box');// 回调函数:尺寸变化时执行
const callback = (entries) => {for (const entry of entries) {const { width, height } = entry.contentRect;console.log(`元素尺寸变化:${width}px × ${height}px`);}
};// 创建观察者实例
const observer = new ResizeObserver(callback);// 开始观察目标元素
observer.observe(target);// 停止观察(必要时)
// observer.unobserve(target);
PerformanceObserver
监测性能指标数据(如页面加载时间、资源加载性能、长任务等),帮助开发者分析和优化网页性能。
- 捕获各种性能相关事件(如 navigation、resource、longtask 等)。
- 异步获取性能数据,不阻塞主线程。
// 监测长任务(阻塞主线程超过50ms的任务)
const observer = new PerformanceObserver((list) => {list.getEntries().forEach(entry => {console.log(`长任务持续时间:${entry.duration}ms`);});
});// 开始观察长任务
observer.observe({ type: 'longtask', buffered: true });
ReportingObserver
收集浏览器生成的各种报告(如 CSP 违规、废弃 API 使用警告、干预报告等),帮助开发者监控应用在生产环境中的问题。
- 捕获浏览器的安全、性能或兼容性相关报告。
- 支持批量处理和缓冲已发生的报告。
// 监测废弃API使用和干预报告
const observer = new ReportingObserver((reports) => {reports.forEach(report => {console.log(`报告类型:${report.type},内容:`, report.body);});
}, { types: ['deprecation', 'intervention'], buffered: true });// 开始观察报告
observer.observe();