目录
一、前言
二、MutationObserver
2.1、基本使用
2.2、API介绍
2.3、常见场景
三、IntersectionObserver
3.1、基本使用
3.2、API介绍
3.3、常见场景
四、ResizeObserver
4.1、基本使用
4.2、API介绍
4.3、常见场景
五、PerformanceObserver
5.1、基本使用
5.2、API介绍
六、ReportingObserver
6.1、基本使用
七、最后
一、前言
浏览器为开发者提供了功能丰富的
Observer
,在这篇文章中,我们将深入研究这些常见的浏览器
Observer
,剖析它们的作用、用法以及它们在
Web
开发中的应用场景。
二、MutationObserver
MutationObserver
用于监听
DOM
对象的变更(包括子节点),当节点属性发生变化,或执行增删改操作时执行对应的
callback
。
MutationObserver
为我们提供了一种十分方便的监听
DOM
变化的方式。
2.1、基本使用
// Observer需要一个用于监听的目标DOM
const targetNode = document.getElementById("app");
//用于确定mutation监听变化的范围
const config = {
attributes: true, // 监听目标节点的属性变化,例如id,class等属性
childList: true, // 除目标节点外还要监听目标节点的直接子节点
subtree: true, // subtree的范围大于childList,还包括子节点children
characterData: true // 监听TextNode需要额外配置,默认TextNode变化不会触发callback
};
// 当观察到变动时执行的回调函数,mutationsList包含本次变更的信息
const callback = function (mutationsList, observer) {
console.log(mutationsList)
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
2.2、API介绍
2.2.1、observe
observe
用于开启对某个
DOM
的监听,一个
MutationObserver
可以通过多次调用
observe
监听多个
DOM
的变化。
当变化发生时
MutationObserver
会将一个或多个
mutation
对象传给
callback
的第一个参数,
mutation
对象内包含本次变更的相关信息下面看一下
mutation
的结构
{
addedNodes: [], //新增DOM时会包含被新增的DOM
attributeName: "id", //本次变更的属性名
attributeNamespace: null, //命名空间URI,一般用不到
nextSibling: null, //当存在添加/删除节点的操作时会存在nextSibling/previousSibling, 引用上一个/下一个兄弟节点
previousSibling: null,
oldValue: null,
removedNodes: [],
target: Text,
type: "characterData" //变更类型,如characterData,childList等
}
2.2.2、
disconnect
observer.disconnect()
调用
observer.disconnect
后
Observer
将不再监听
target
,如果不需要监听请及时调用该方法,以免产生预期之外的行为以及内存泄漏。
2.2.3、
takeRecords
takeRecords
用于获取在事件队列中但还未传递给
callback
的
mutation
对象,通常使用在调用
disconnect
时又不想丢失之前的
mutationRecords
(如果
mutation
连续触发,可能出现
mutation
还在队列中但未传递给
callback
的情况)。
2.3、常见场景
对于需要监听
DOM
变化的场景可考虑使用
MutationObserver
,利于用于
Tag group
内元素的动态渲染,下面使用
MutationObserver
实现一个简单的
Todo List
2.3.1、源码
MutationObserver To-Do List Demo
待办事项列表
- 完成作业
- 购物
任务数量:2
2.3.2、预览
在线源码请点击【
前往
】
2.3.3、效果
三、IntersectionObserver
IntersectionObserver
用于监听一个元素的可见比例(一个
DOM
元素被另一个
DOM
元素遮挡百分比)变化。
3.1、基本使用
const target = document.getElementById('app');
const options = {
root: rootTarget, // 相对于某个元素进行遮挡计算
rootMargin: '0px', // 进行计算的边界范围,通过rootMargin可以实现提前计算或延迟计算(相对于root原本尺寸)的效果
threshold: 0.5 // 触发callback时的遮挡比例,0.5代表元素被遮挡50%时触发callback。由于浏览器事件循环机制的影响,callback触发时遮挡比例通常不会是精确的50%。
};
const intersectionObserver = new IntersectionObserver((entries, observer) => {
//和MutationObserver相同,也是产生一个array
entries.forEach(entry => {
console.log(entry)
});
}, options);
intersectionObserver.observe(target);
3.2、API介绍
3.2.1、observe & options
observe
方法用于启动一个
Observer
对
DOM
元素的监听。在创建
IntersectionObserver
时可以通过传入
option
改变监听的行为。
const options = {
root: root,
rootMargin: '100px',
threshold: 0.7
};
在上面的配置中,通过配置
rootMargin
为
100px
在
target
距离
root
元素
100px
时即可判定为被遮挡,通过
threshold
设置为
0.7
,当遮挡比例查过
70%
时执行
callback
。
3.2.2、entry
callback
第一个
param
是
entry
对象构成的
array
,
entry
包含了触发
callback
时
DOM
的位置信息
//被监听DOM元素的Rect信息
boundingClientRect: {
bottom: 208
height: 200
left: 8
right: 208
top: 8
width: 200
x: 8
y: 8
}
intersectionRatio: 1 //交叉比例
// 被监听元素与Root元素交叉部分矩形的Rect信息。
intersectionRect: {
bottom: 208,
height: 200,
left: 8,
right: 208,
top: 8,
width: 200,
x: 8,
y: 8
},
// 是否处于交叉状态
isIntersecting: true,
isVisible: false,
// Root元素的Rect信息
rootBounds: {
bottom: 606,
height: 606,
left: 0,
right: 476,
top: 0,
width: 476,
x: 0,
y: 0
},
// root元素
target: div#target,
time: 49.09999990463257
3.3、常见场景
乍一看
IntersectionObserver
好像没啥用,单这个
Api
在某些场景下十分好用。
比如我们有一个通过
sticky
固定在屏幕顶部的
header
元素,我们希望在触发
sticky
时给
header
加一个
shadow
(很多
table
都有这样的功能)
一种很常见的做法是监听
scroll
,当滚动一定距离时加上
shadow
即可。但是监听
scroll
本身会早成一定的渲染压力(
scroll
触发非常频繁),同时如果使用
React
这样的框架又会造成额外的
render
,在用户的视角看来更卡了。
此时使用
IntersectionObserver
就很合适了,因为我们需要监听的只是触发
sticky
的一瞬间,其他的滚动都是无效的,没必要进行计算。
3.3.1、源码
Sticky Header with Shadow on Intersection
Sticky Header
向下滚动触发sticky时展示shadow
3.3.2、预览
在线源码请点击【
前往
】
3.3.3、效果
四、ResizeObserver
ResizeObserver
是用于监听
DOM
尺寸变化的
observer
,当
DOM
尺寸变化是执行
callback
4.1、基本使用
和前面的
api
用法差不多,这里不过多介绍。
const box = document.getElementById('box');
const resizeObserver = new ResizeObserver(entries => {
entries.forEach(entry => {
console.log(entry)
});
});
resizeObserver.observe(box);
4.2、API介绍
entry
对象包含
resize
相关的信息,下面看一下
entry
的结构
{
// 不同box-sizing下的尺寸
borderBoxSize: [{
blockSize: 200,
inlineSize: 200,
}],
contentBoxSize: [{
blockSize: 200,
inlineSize: 200,
}],
contentRect: {
bottom: 200,
height: 200,
left: 0,
right: 200,
top: 0,
width: 200,
x: 0,
y: 0
},
// 在物理设备像素上的大小, 在不同的屏幕上尺寸不同例如Retina
devicePixelContentBoxSize: [{
blockSize: 300,
inlineSize: 300
}
],
target: div#resizable-box
}
4.3、常见场景
可以基于
ResizeObserver
实现一个简单的
resize-detector
(参考
react-resize-detector
),在尺寸变化时返回尺寸信息,点击盒子就算拖拽有效。
4.3.1、源码
ResizeObserver Demo with Resizable Box
Resize me!
4.3.2、预览
在线源码请点击【
前往
】
4.3.3、效果
五、PerformanceObserver
PerformanceObserver
用于监听浏览器的
performance
事件,方便在
performance
事件触发时作统一处理。
5.1、基本使用
// mdn demo
function perf_observer(list, observer) {
console.log(list)
}
var observer2 = new PerformanceObserver(perf_observer);
// entryTypes用于指定要监听的事件类型
observer2.observe({ entryTypes: ["measure"] });
5.2、API介绍
下面列一下常见的
entryTypes
mark
:用于标记时间戳的事件
measure
:
performance.measure
触发的事件
frame
:网页渲染的事件
navigation
:导航的事件,例如页面加载或重新加载
resource
:资源加载事件
longtask
:长任务事件
paint
:绘制事件,例如
FP
,
FCP
layout-shift
:用于监视布局变化的事件
对于对性能比较敏感的项目以及长期性能监控来说这个
api
还是比较方便的。
六、ReportingObserver
ReportingObserver
用于监听浏览器报告的事件,例如废弃
API
,过时特性,网络错误。做监控
SDK
的同学应该经常能用到,日常业务代码用的比较少。
6.1、基本使用
这里就简单看一下使用方法吧,比较简单
const observer = new ReportingObserver((reports, observer) => {
reports.forEach(report => {
console.log(report);
});
});
// 监听过时特性
observer.observe({ types: ['deprecation'] });
七、最后
到此这篇关于JavaScript中5个重要的Observer函数小结的文章就介绍到这了,更多相关JavaScript Observer内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
Vue.js原理分析之observer模块详解
JavaScript编程设计模式之观察者模式(Observer Pattern)实例详解
JavaScript中MutationObServer监听DOM元素详情
JavaScript API ResizeObserver使用示例
原生JS Intersection Observer API实现懒加载
RxJS中的Observable和Observer示例详解
