现代浏览器观察者Observer
| IntersectionObserver | MutationObserver | ResizeObserver | PerformanceObserver | |
| 作用 | 观察一个元素是否在视窗可见 | 观察DOM中的变化 | 观察视口大小的变化 | 坚持测性能度量事件 |
| 方法 |
observe() disconnect() takeRecords() |
observe() disconnect() takeRecords() unobserve() |
observe() disconnect() unobserve() |
observe() disconnect() takeRecords() |
| 取代 | DOM Mutation events |
getBoundingClientRect()返回元素的大小及其相对于可视窗口的位置 Scroll和Resize事件 |
Resize事件 | Performance接口 |
| 用途 |
|
|
|
|
IntersectionObserver 交叉观察者
1.创建观察者
const options = {
root:document.getElementById('zjy'),
rootMargin:'0px',
threshold:[0.3,0.5,0.8,1]
}
const observer = new IntersectionObserver(handler,options)
root指定一个根元素
rootMargin使用与类似设置css边距的语法来指定根边距(根元素观察影响的范围)
threshold阈值,可以为数组。[0.3]表示当目标元素在根元素指定的元素内可见30%时,调用处理函数。
2.定义回调函数
function handler (entries, observer) {
entries.forEach(entry => {
// 每个成员都是一个IntersectionObserverEntry对象。
// 举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。
// entry.boundingClientRect 目标元素的位置信息
// entry.intersectionRatio 目标元素的可见比例
// entry.intersectionRect 交叉部分的位置信息
// entry.isIntersecting
// entry.rootBounds 根元素的位置
// entry.target
// entry.time 时间戳
});
}
可以在handler中做自己想做的事,例如:
entry.target.src = entry.target.dataset.src; observer.unobserve(entry.target);
3.定义要观察的目标对象
const domArr = document.querySelectorAll(“img”);
domArr.forEach((t)=>{
observer.observe(t);
})
MutationObserver 变动观察者
接口提供了对DOM树所做更改的能力。它被设计而为旧的MutationEvents功能的替代品,该功能是DOM3 Events 规范的一部分。
使用方式
1.定义观察者
let observer new MutationObserver(cb)
2.定义回调函数
function cb(mutations,observer){
mutations.forEach((mutation)=>{
//输出变更记录
console.log(mutation)
})
}
每个mutation都对应一个MutationRecord对象,记录着DOM每次发生变化的变化记录。
MutationRecord对象包含的DOM相关信息如下:
| 属性 | 意义 |
| type | 观察的变动类型(attribute、characterData或者childList) |
| target | 发生变动的DOM节点 |
| addedNodes | 新增的DOM节点 |
| removedNodes | 删除的DOM节点 |
| previousSibling | 前一个同级节点,如果没有则返回null |
| nextSibling | 下一个同级节点,如果没有则返回null |
| attributeName | 发生变动的属性。如果设置了attributeFilter,则只返回预先指定的属性 |
| oldValue | 变动前的值。这个属性只对attribute和characterData变动有效,如果发生childList变动,只返回null |
3.定义要观察的目标对象
observer.observe(content, {
attributes: true, // Boolean - 观察目标属性的改变
characterData: true, // Boolean - 观察目标数据的改变(改变前的数据/值)
childList: true, // Boolean - 观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化
subtree: true, // Boolean - 目标以及目标的后代改变都会观察
attributeOldValue: true, // Boolean - 表示需要记录改变前的目标属性值
characterDataOldValue: true, // Boolean - 设置了characterDataOldValue可以省略characterData设置
// attributeFilter: ['src', 'class'] // Array - 观察指定属性
});
- 第一参数:被观察的
DOM节点。 - 第二参数:配置需要观察的变动项
options。
ResizeObserver 视图观察者
ResizeObserver API是一个新的JavaScript API,与IntersectionObserver API非常相似,它们都允许我们去监听某个元素的变化。
使用方式与MutationObserver大致相同 简单描述一下
//创建观察者
let observer = new ResizeObserver(callback);
//定义回调函数
function callback(entries){
entries.forEach((entry)=>{
console.log(entry)
})
}
//定义要观察的目标对象
observer.observe(document.body)
介绍一下entry对象,包含两个属性contentRect和target
contentRect一些位置信息
| 属性 | 作用 |
| bottom | top + height 的值 |
| height | 元素本身的高度,不包含padding、border的值 |
| left | padding-left的值 |
| right | left + width 的值 |
| top | padding-top 的值 |
| width | 元素本身的宽度,不包含padding 、border的值 |
| x | 大小与top相同 |
| y | 大小与left相同 |
PerformanceObserver 性能观察者
这是一个浏览器和Node.js 里都存在的API,采用相同W3C的Performance Timeline规范
- 在浏览器中,我们可以使用 window 对象取得
window.performance和window.PerformanceObserver。 - 而在
Node.js程序中需要perf_hooks取得性能对象
const { PerformanceObserver, performance } = require('perf_hooks');
//创建观察者
let observer = new PerformanceObserver(callback);
//定义回调函数事件
function callback(list, observer){
const entries = list.getEntries();
entries.forEach((entry) => {
console.log(“Name: “ + entry.name + “, Type: “ + entry.entryType + “, Start: “ + entry.startTime + “, Duration: “ + entry.duration + “\n”);
});
}
//定义要观察的目标对象
observer.observe({entryTypes: ["entryTypes"]});
每一个list都是一个完整的PerformanceObserverEntryList对象,包含三个方法getEntries、getEntriesByType、getEntriesByName
| 方法 | 作用 |
| getEntries() | 返回一个列表,该列表包含一些用于承载各种性能数据的对象,不做任何过滤 |
| getEntriesByType() | 返回一个列表,该列表包含一些用于承载各种性能数据的对象,按类型过滤 |
| getEntriesByName() | 返回一个列表,,该列表包含一些用于承载各种性能数据的对象,按名称过滤 |
observer.observe(...)方法接受可以观察到的有效的入口类型。这些输入类型可能属于各种性能API,比如User timing或Navigation Timing API。有效的entryType值:
| 属性 | 别名 | 类型 | 描述 |
|
frame navigation |
PerformanceFrameTiming PerformanceNavigationTiming |
URL | 文件的地址 |
| resource | PerformanceResourceTiming | URL | 所请求资源的解析URL |
| mark | PerformanceMark | DOMString | 通过调用创建标记时使用的名称performance.mark() |
| measure | PerformanceMeasure | DOMString | 通过调用创建度量时使用的名称performance.measure() |
| paint | PerformancePaintTiming | DOMString | 无论是'first-paint'或'first-contentful-paint' |
| longtask | PerformanceLongTaskTiming | DOMString | 报告长任务的实例 |
静态资源监控示例代码
function filterTime(a, b) {
return (a > 0 && b > 0 && (a - b) >= 0) ? (a - b) : undefined;
}
let resolvePerformanceTiming = (timing) => {
let o = {
initiatorType: timing.initiatorType,
name: timing.name,
duration: parseInt(timing.duration),
redirect: filterTime(timing.redirectEnd, timing.redirectStart), // 重定向
dns: filterTime(timing.domainLookupEnd, timing.domainLookupStart), // DNS解析
connect: filterTime(timing.connectEnd, timing.connectStart), // TCP建连
network: filterTime(timing.connectEnd, timing.startTime), // 网络总耗时
send: filterTime(timing.responseStart, timing.requestStart), // 发送开始到接受第一个返回
receive: filterTime(timing.responseEnd, timing.responseStart), // 接收总时间
request: filterTime(timing.responseEnd, timing.requestStart), // 总时间
ttfb: filterTime(timing.responseStart, timing.requestStart), // 首字节时间
};
return o;
};
let resolveEntries = (entries) => entries.map(item => resolvePerformanceTiming(item));
let resources = {
init: (cb) => {
let performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance;
if (!performance || !performance.getEntries) {
return void 0;
}
if (window.PerformanceObserver) {
let observer = new window.PerformanceObserver((list) => {
try {
let entries = list.getEntries();
cb(resolveEntries(entries));
} catch (e) {
console.error(e);
}
});
observer.observe({
entryTypes: ['resource']
})
} else {
window.addEventListener('load', () => {
let entries = performance.getEntriesByType('resource');
cb(resolveEntries(entries));
});
}
},
};

浙公网安备 33010602011771号