跳转到主内容
极星编程网:以代码为星,赴技术山海!

JavaScript中5个重要的Observer函数小结

目录 一、前言 二、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时展示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示例详解

相关文章