MutationObserver 监听DOM树变化

1 概述

Mutation observer 是用于代替 Mutation events 作为观察DOM树结构发生变化时,做出相应处理的API。为什么要使用mutation observer 去代替 mutation events 呢,我们先了解一下mutation events

Mutation Events

Mutation events 是在 DOM3中定义,用于监听DOM树结构变化的事件

它简单的用法如下:

document.getElementById('list').addEventListener("DOMSubtreeModified", function(){
  console.log('列表中子元素被修改');
}, false);

Mutation 事件列表

  • DOMAttrModified
  • DOMAttributeNameChanged
  • DOMCharacterDataModified
  • DOMElementNameChanged
  • DOMNodeInserted
  • DOMNodeRemoved
  • DOMNodeInsertedIntoDocument
  • DOMSubtreeModified

其中DOMNodeRemoved,DOMNodeInserted 和 DOMSubtreeModified 分别用于 监听元素子项的删除,新增,修改(包括删除和新增),
DOMAttrModified 是监听元素属性的修改,并且能够提供具体的修改动作。

Mutation Events遇到的问题
  • 浏览器兼容性问题
    IE9不支持Mutation Events
    Webkit内核不支持DOMAttrModified特性,
    DOMElementNameChanged和DOMAttributeNameChanged 在Firefox上不被支持。
  • 性能问题
    1.Mutation Events是同步执行的,它的每次调用,都需要从事件队列中取出事件,执行,然后事件队列中移除,期间需要移动队列元素。如果事件触发的较为频繁的话,每一次都需要执行上面的这些步骤,那么浏览器会被拖慢。
    2.Mutation Events本身是事件,所以捕获是采用的是事件冒泡的形式,如果冒泡捕获期间又触发了其他的MutationEvents的话,很有可能就会导致阻塞Javascript线程,甚至导致浏览器崩溃。

Mutation Observer

Mutation Observer 是在DOM4中定义的,用于替代 mutation events 的新API,它的不同于events的是,所有监听操作以及相应处理都是在其他脚本执行完成之后异步执行的,并且是所以变动触发之后,将变得记录在数组中,统一进行回调的,也就是说,当你使用observer监听多个DOM变化时,并且这若干个DOM发生了变化,那么observer会将变化记录到变化数组中,等待一起都结束了,然后一次性的从变化数组中执行其对应的回调函数。

Mutation Observer 的浏览器兼容范围


兼容性

2 方法

构造函数

用来实例化一个Mutation观察者对象,其中的参数是一个回调函数,它是会在指定的DOM节点发送变化后,执行的函数,并且会被传入两个参数,一个是变化记录数组(MutationRecord),另一个是观察者对象本身

new MutationObserver(function(records, itself){});
observe

在观察者对象上,注册需要观察的DOM节点,以及相应的参数

void observe(Node target, optional MutationObserverInit options)

其中的可选参数 MutationObserverInit的属性如下:

childLIst 观察目标节点的子节点的新增和删除。
attributes 观察目标节点的属性节点(新增或删除了某个属性,以及某个属性的属性值发生了变化)。
characterData 如果目标节点为characterData节点(一种抽象接口,具体可以为文本节点,注释节点,以及处理指令节点)时,也要观察该节点的文本内容是否发生变化
subtree 观察目标节点的所有后代节点(观察目标节点所包含的整棵DOM树上的上述三种节点变化)
attributeOldValue 在attributes属性已经设为true的前提下, 将发生变化的属性节点之前的属性值记录下来(记录到下面MutationRecord对象的oldValue属性中)
characterDataOldValue 在characterData属性已经设为true的前提下,将发生变化characterData节点之前的文本内容记录下来(记录到下面MutationRecord对象的oldValue属性中)
attributeFilter 一个属性名数组(不需要指定命名空间),只有该数组中包含的属性名发生变化时才会被观察到,其他名称的属性发生变化后会被忽略想要设置那些删选参数的话,

如果想要使用哪个参数的话,就将其值设定为true

disconnect

暂定在观察者对象上设置的节点的变化监听,直到重新调用observe方法

takeRecords

在观察者对象上调用takeRecords 会返回 其观察节点上的变化记录(MutationRecord)数组
其中MutationRecord数组也会作为,观察者初始化时的回调函数的第一个参数
其包含的属性如下:

type 如果是属性发生变化,则返回attributes.如果是一个CharacterData节点发生变化,则返回characterData,如果是目标节点的某个子节点发生了变化,则返回childList.
target 返回此次变化影响到的节点,具体返回那种节点类型是根据type值的不同而不同的,如果type为attributes,则返回发生变化的属性节点所在的元素节点,如果type值为characterData,则返回发生变化的这个characterData节点.如果type为childList,则返回发生变化的子节点的父节点.
addedNodes 返回被添加的节点
removedNodes 返回被删除的节点
previousSibling 返回被添加或被删除的节点的前一个兄弟节点
nextSibling 返回被添加或被删除的节点的后一个兄弟节点
attributeName 返回变更属性的本地名称
oldValue 根据type值的不同,返回的值也会不同.如果type为attributes,则返回该属性变化之前的属性值.如果type为characterData,则返回该节点变化之前的文本数据.如果type为childList,则返回null

3 使用实例

// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
// 选择目标节点
var target = document.querySelector('#some-id'); 
// 创建观察者对象
var observer = new MutationObserver(function(mutations) {  
  mutations.forEach(function(mutation) { 
    console.log(mutation.type); 
  }); 
}); 
// 配置观察选项:
var config = { attributes: true, childList: true, characterData: true } 
// 传入目标节点和观察选项
observer.observe(target, config); 
// 随后,你还可以停止观察
observer.disconnect();

4 参考链接

[1].MDN Mutation Observer
[2].将突变事件和属性更改事件迁移到突变观察者

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容