了解HTML5中的MutationObserver

了解HTML5中的MutationObserverMutationObse 翻译过来就是变动观察器 字面上就可以理解这是用来观察 Node 节点 变化的 MutationObse 是在 DOM4 规范中定义的 它的前身是 MutationEven 事件 该事件最初在 DOM2 事件规范中介绍 到来了 DOM3 事件规范中正式定义 但是由于该事件存在兼容性以及性能上的问题被弃用 MutationEven 虽然 MutationEven 已经被弃用

MutationObserver翻译过来就是变动观察器,字面上就可以理解这是用来观察Node(节点)变化的。MutationObserver是在DOM4规范中定义的,它的前身是MutationEvent事件,该事件最初在DOM2事件规范中介绍,到来了DOM3事件规范中正式定义,但是由于该事件存在兼容性以及性能上的问题被弃用。

MutationEvent

虽然MutationEvent已经被弃用,但是我们还是需要了解它,可能你会为了浏览器兼容性的问题而遇到它(万恶的浏览器兼容性)。

MutationEvent总共有7种事件:DOMNodeInsertedDOMNodeRemovedDOMSubtreeModifiedDOMAttrModified
DOMCharacterDataModifiedDOMNodeInsertedIntoDocumentDOMNodeRemovedFromDocument

MutationEvent的兼容性:

  1. MutationEvent在IE浏览器中最低支持到IE9
  2. 在webkit内核的浏览器中,不支持DOMAttrModified事件
  3. IE,Edge以及Firefox浏览器下不支持DOMNodeInsertedIntoDocumentDOMNodeRemovedFromDocument事件
document.addEventListener('DOMNodeInserted', function() { var newEl = document.createElement('div'); document.body.appendChild(newEl); });

document下的所有DOM添加操作都会触发DOMNodeInserted方法,这时就会出现循环调用DOMNodeInserted方法,导致浏览器崩溃。还有就是MutationEvent是事件机制,因此会有一般事件都存在的捕获和冒泡阶段,此时如果在捕获和冒泡阶段又对DOM进行了操作会拖慢浏览器的运行。

另一点就是MutationEvent事件机制是同步的,也就是说每次DOM修改就会触发,修改几次就触发几次,严重降低浏览器的运行,严重时甚至导致线程崩溃

 
  
var i=0; block.addEventListener('DOMNodeInserted', function(e) { i++ }); block.appendChild(docuemnt.createTextNode('1')); console.log(i) //1 block.appendChild(docuemnt.createTextNode('2')); console.log(i) //2 block.appendChild(docuemnt.createTextNode('3')); console.log(i) //3

再看个例子:

 
  
Text
block.addEventListener('DOMNodeInserted', function(e) { console.log('1'); //1 }); span.appendChild(docuemnt.createTextNode('other Text'));

span元素中添加节点会触发block中的DOMNodeInserted事件,可是你只想观察block的变化,不想观察block中子节点的变化,这时你不得不在DOMNodeInserted事件中进行过滤,把对span的操作忽略掉,这无疑增加了操作的复杂性。

MutationObserver

了解HTML5中的MutationObserver

 

我们可以看到MutationObserver在IE中最低要就是IE11,如果你的网站不需要支持IE或者只支持到IE11,那么你可以放心的使用MutationObserver,否则你可能需要用到上面提到的MutationEvent事件,当然如果你的网站还要支持IE8及以下版本,那么你只能和Mutation说拜拜了。

MutationObserver是一个构造器,接受一个callback参数,用来处理节点变化的回调函数,返回两个参数,mutations:节点变化记录列表(sequence

),observer:构造MutationObserver对象。

var observe = new MutationObserver(function(mutations,observer){ })

MutationObserver对象有三个方法,分别如下:

  1. observe:设置观察目标,接受两个参数,target:观察目标,options:通过对象成员来设置观察选项
  2. disconnect:阻止观察者观察任何改变
  3. takeRecords:清空记录队列并返回里面的内容

关于observe方法中options参数有已下几个选项:

  1. childList:设置true,表示观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化
  2. attributes:设置true,表示观察目标属性的改变
  3. characterData:设置true,表示观察目标数据的改变
  4. subtree:设置为true,目标以及目标的后代改变都会观察
  5. attributeOldValue:如果属性为true或者省略,则相当于设置为true,表示需要记录改变前的目标属性值,设置了attributeOldValue可以省略attributes设置
  6. characterDataOldValue:如果characterData为true或省略,则相当于设置为true,表示需要记录改变之前的目标数据,设置了characterDataOldValue可以省略characterData设置
  7. attributeFilter:如果不是所有的属性改变都需要被观察,并且attributes设置为true或者被忽略,那么设置一个需要观察的属性本地名称(不需要命名空间)的列表

下表描述了MutationObserver选项与MutationEvent名称之间的对应关系:

MutationEvent MutationObserver options
DOMNodeInserted { childList: true, subtree: true }
DOMNodeRemoved { childList: true, subtree: true }
DOMSubtreeModified { childList: true, subtree: true }
DOMAttrModified { attributes: true, subtree: true }
DOMCharacterDataModified { characterData: true, subtree: true }

从上表我们也可以看出相比与MutationEvent而言MutationObserver极大地增加了灵活性,可以设置各种各样的选项来满足程序员对目标的观察。

我们简单看几个例子:

 
  
target的第一个子节点

target的后代

1.callback的回调次数

var target=document.getElementById('target'); var i=0 var observe=new MutationObserver(function (mutations,observe) { i++ }); observe.observe(target,{ childList: true}); target.appendChild(docuemnt.createTextNode('1')); target.appendChild(docuemnt.createTextNode('2')); target.appendChild(docuemnt.createTextNode('3')); console.log(i) //1

MutationObserver的callback回调函数是异步的,只有在全部DOM操作完成之后才会调用callback。

2.当只设置{ childList: true}时,表示观察目标子节点的变化

var observe=new MutationObserver(function (mutations,observe) { debugger; console.log(mutations); //observe.discount(); }); observe.observe(target,{ childList: true}); target.appendChild(document.createTextNode('新增Text节点')); //增加节点,观察到变化 target.childNodes[0].remove(); //删除节点,可以观察到 target.childNodes[0].textContent='改变子节点的后代'; //不会观察到

如果想要观察到子节点以及后代的变化需设置{childList: true, subtree: true}

attributes选项用来观察目标属性的变化,用法类似与childList,目标属性的删除添加以及修改都会被观察到。

3.我们需要注意的是characterData这个选项,它是用来观察CharacterData类型的节点的,只有在改变节点数据时才会观察到,如果你删除或者增加节点都不会进行观察,还有如果对不是CharacterData类型的节点的改变不会观察到,比如:

observe.observe(target,{ characterData: true, subtree: true}); target.childNodes[0].textContent='改变Text节点'; //观察到 target.childNodes[1].textContent='改变p元素内容'; //不会观察到 target.appendChild(document.createTextNode('新增Text节点')); //不会观察到 target.childNodes[0].remove(); //删除TEXT节点也不会观察到

我们只需要记住只有对CharacterData类型的节点的数据改变才会被characterData为true的选项所观察到。

4.最后关注一个特别有用的选项attributeFilter,这个选项主要是用来筛选要观察的属性,比如你只想观察目标style属性的变化,这时可以如下设置:

observe.observe(target,{ attributeFilter: ['style'], subtree: true}); target.style='color:red'; //可以观察到 target.removeAttribute('name'); //删除name属性,无法观察到 

disconnect方法是用来阻止观察的,当你不再想观察目标节点的变化时可以调用observe.disconnect()方法来取消观察。

takeRecords方法是用来取出记录队列中的记录。它的一个作用是,比如你对一个节点的操作你不想马上就做出反应,过段时间在显示改变了节点的内容。

var observe=new MutationObserver(function(){}); observe.observe(target,{ childList: true}); target.appendChild(document.createTextNode('新增Text节点')); var record = observe.takeRecords(); //此时record保存了改变记录列表 //当调用takeRecords方法时,记录队列被清空因此不会触发MutationObserver中的callback回调方法。 target.appendChild(document.createElement('span')); observe.disconnect(); //停止对target的观察。 //MutationObserver中的回调函数只有一个记录,只记录了新增span元素 //之后可以对record进行操作 //...

MutationRecord
变动记录中的属性如下:

  1. type:如果是属性变化,返回”attributes”,如果是一个CharacterData节点(Text节点、Comment节点)变化,返回”characterData”,节点树变化返回”childList”
  2. target:返回影响改变的节点
  3. addedNodes:返回添加的节点列表
  4. removedNodes:返回删除的节点列表
  5. previousSibling:返回分别添加或删除的节点的上一个兄弟节点,否则返回null
  6. nextSibling:返回分别添加或删除的节点的下一个兄弟节点,否则返回null
  7. attributeName:返回已更改属性的本地名称,否则返回null
  8. attributeNamespace:返回已更改属性的名称空间,否则返回null
  9. oldValue:返回值取决于type。对于”attributes”,它是更改之前的属性的值。对于”characterData”,它是改变之前节点的数据。对于”childList”,它是null

其中 typetarget这两个属性不管是哪种观察方式都会有返回值,其他属性返回值与观察方式有关,比如只有当attributeOldValue或者characterDataOldValue为true时oldValue才有返回值,只有改变属性时,attributeName才有返回值等。

转载于:https://segmentfault.com/a/87829

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229316.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午4:58
下一篇 2026年3月16日 下午4:59


相关推荐

  • .java文件怎么在cmd中运行(以Helloworld为例)

    .java文件怎么在cmd中运行(以Helloworld为例)Java环境的配置#-欢迎使用Markdown编辑器你好!这是你第一次使用Markdown编辑器所展示的欢迎页。如果你想学习如何使用Markdown编辑器,可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:全新的界面设计,将会带来全新的写作体验;在创作中心设置你喜爱的代码高亮样式,Markdown将代码片显示选择的高亮样式

    2022年5月27日
    92
  • cisco fabricpath 功能介绍

    cisco fabricpath 功能介绍网络架构师希望成长中的数据中心运行速度越来越快 让用户越来越满意 管理越来越简单 思科表示其 FabricPath 技术可以满足这三大愿望 它使数据中心交换机之间的连接比传统的生成树协议 STP 更好 在这个独家测试中 我们评估了 FabricPath 在提高带宽 重整问题路由和简化网络管理方面的能力 在这三个方面 FabricPath 最终提交了满意的答卷 思科采用了 IETF 即将发布

    2026年3月26日
    4
  • 基于51单片机的八位流水灯(三种形式)

    基于51单片机的八位流水灯(三种形式)写一下寒假做的51小项目。基于AT89C51的流水灯:流水灯共八个,可以实现交替闪烁,一起闪烁,左右流水灯等效果。模式一:按动key1,实现1,3,5,7和2,4,6,8交替闪烁;模式二:按动key2,实现D1→D8流水灯效果;模式三:按动key3,实现全部闪烁效果,时间间隔为0.5秒;模式四:按动key4,实现D8→D1流水灯效果;模式1:使用P1的取反和delay延时实现模式2…

    2022年6月10日
    37
  • 免费申请国外免费域名超详细教程

    免费申请国外免费域名超详细教程1.首先申请免费域名网站:https://my.freenom.com/domains.php2.填入域名,这里我们以xcflag为列(尽量选择复杂一点的或者五个字母以上的域名,因为简单的有些域名是需要收费的),点击检查可用性。3.可以看到很多免费的域名(用的谷歌翻译插件,翻译有时候不是很准确,free翻译过来应该是免费而不是自由,之后会写一些关于谷歌插件的笔记,详细讲解)4.我们选择xcflag.tk点击立即获取,稍等一会点击购物车查看绿色按钮5.默认三个月试用,这里下拉框我们选择十二个月

    2022年6月30日
    101
  • 块级元素和行内元素(重点)

    块级元素和行内元素(重点)块级元素和行内元素 重点 块级元素每个块级元素通常都会独占一行或者是多行 可以对其单独设置高度 宽度以及对齐等属性 常见的块级元素有 h1 h6 p div ul ol li 等块级元素的特点 块级元素会独占一行高度 行高 外边距和内边距都可以单独设置宽度默认是容器的 1 li ol ul div p h6 h1

    2026年3月19日
    3
  • C string转int

    C string转intC string 转 intintintA 0 intA int Parse str 1int TryParse str outintA 2intA Convert ToInt32 str 3 以上都可以 其中 1 和 3 需要 try 异常 2 不需要 inti 1 boolb int TryParse null outi 执

    2026年3月20日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号