当前位置: 首页 > Web前端 > CSS

JavaScript第十工作原理——使用MutationObserver监控DOM变化

时间:2023-03-31 01:42:47 CSS

原文请看这里,略有删节。本文根据知识共享署名4.0国际许可协议共享,作者:Troland。本系列持续更新中,Github地址请查看这里。这是JavaScript工作原理的第10章。网络应用在客户端越来越复杂,这是由多种因素造成的,比如需要更丰富的界面交互来提供更复杂的应用功能、实时计算等。Web应用程序日益复杂,使得在其生命周期的给定时刻了解交互界面的准确状态变得不可能。如果你正在构建一些框架或者库,那就更难了,比如你不能监听DOM来响应和执行一些特定的操作。概述MutationObserver是现代浏览器提供的用于检测DOM变化的Web界面。您可以使用此接口来侦听新的或删除的节点、属性更改或文本节点内容更改。我能做些什么?在以下情况下,您可以方便地使用MutationObserver接口。例如:通知用户他当前所在的页面发生了一些变化。使用一些很棒的JavaScript框架,根据DOM变化动态加载JavaScript模块。或许你在开发所见即所得的编辑器时,使用MutationObserver接口可以及时收集任何时间点的变化,从而轻松实现undo/redo功能。这些只是MutationObserver使用场景的一部分。如何使用MutationObserver在您的应用程序中集成MutationObserver非常简单。通过将函数作为参数传递给构造函数MutationObserver来初始化MutationObserver实例,每次DOM更改时都会调用该函数。MutationObserver函数的第一个参数是单个批次中的一组DOM更改。每个更改都包含更改类型和发生的更改。varmutationObserver=newMutationObserver(function(mutations){mutations.forEach(function(mutation){console.log(mutation);});});创建的实例对象有3个方法:observe-startmonitoring。接收两个参数——要监视的DOM节点和一个配置对象。disconnect-停止监听变化。takeRecords-在触发回调之前返回最新的批处理DOM更改。以下是开始监听的代码片段://开始监听页面根元素中的HTML变化。mutationObserver.observe(document.documentElement,{attributes:true,characterData:true,childList:true,subtree:true,attributeOldValue:true,characterDataOldValue:true});现在,假设你写了一个简单的div元素:").removeAttr("类");调用mutationObserver时。observe(…)可以开始监听DOM的变化。每次发生DOM突变时都会打印每条MutationRecord日志消息:此更改是由于删除类属性引起的。最后,如果你想停止监听DOM变化,可以使用下面的方法://MutationObserver停止监听DOM变化mutationObserver.disconnect();现在,MutationObserver浏览器兼容性非常好:替代方法但是,MutationObserver之前并没有被广泛使用。那么,在没有MutationObserver的情况下,开发者如何解决监控DOM变化的问题呢?有几种方法可用:轮询MutationEventsCSS动画轮询最简单粗暴的方法是使用轮询。使用浏览器内置的setInterval网络界面,您可以创建一个cron作业来定期检查DOM的变化。当然,这种方法会显着降低Web应用程序/网站的性能。其实这个可以理解为脏检查。如果你用过AngularJS,你应该看到它的脏检查带来的性能问题。我在我的另一个系列里稍微介绍过,你可以在这里查看详情。MutationEvents早在2000年,就推出了MutationEventsAPI。虽然它有效,但每个DOM更改都会触发一个突变事件,这会再次产生性能问题。现在,MutationEvents接口已被弃用,所有现代浏览器都将在不久的将来停止支持它。下面是MutationEvents的浏览器兼容性:依赖CSS动画的CSS动画是一个有点新颖的替代方案。这听起来可能令人困惑。基本上,这个想法是创建一个动画,一旦一个元素被添加到DOM就会被触发。animationstart事件在CSS动画开始时被触发:如果你给这个事件添加一个事件监听器,你就可以准确地知道什么时候向DOM添加元素。动画的运行时间段必须很短,让用户感觉不到,即体验更好。首先需要一个父元素来监听节点的添加事件:

为了处理节点的添加,需要创建一个关键帧序列动画,即添加节点启动时:@keyframesnodeInserted{from{opacity:0.99;}至{不透明度:1;}}创建关键帧后,对需要监控的元素应用动画。注意持续时间短——动画轨迹在浏览器端会很平滑(即用户不会感觉到动画正在发生):#container-element*{animation-duration:0.001s;animation-name:nodeInserted;}像这样将对容器元素的所有后代节点进行动画处理。当动画结束时,将触发插入事件。我们需要创建一个函数作为事件监听器。在函数内部,一开始必须使用event.animationName代码进行检查,以确保它是我们正在收听的动画。varinsertionListener=function(event){//确保是被监听的动画if(event.animationName==="nodeInserted"){console.log("Nodehasbeeninserted:"+event.target);}}为父Element绑定事件监听器:document.addEventListener(“animationstart”,insertionListener,false);//标准+firefoxdocument.addEventListener(“MSAnimationStart”,insertionListener,false);//IEdocument.addEventListener(“webkitAnimationStart”,insertionListener,false);//Chrome+Safari在这里使用了事件委托。CSS动画浏览器支持:与上述备选方案相比,MutationObserver有几个优点。本质上,它会监听DOM中的每一个可能的变化,并且具有更好的性能,因为它会在一批DOM变化后触发回调事件。总之,MutationObserver的兼容性很好,还有一些shim,是基于MutationEvents的。本系列持续更新中,Github地址请查看这里。