(转载)了解 HTML5 中的 MutationObserver
MutationObserver
翻译过来就是变动观察器,字面上就可以理解这是用来观察 Node
(节点)变化的。MutationObserver
是在 DOM4
规范中定义的,它的前身是 MutationEvent
事件,该事件最初在 DOM2
事件规范中介绍,到来了 DOM3
事件规范中正式定义,但是由于该事件存在兼容性以及性能上的问题被弃用。兼容性查阅
MutationObserver
是一个构造器,接受一个 callback
参数,用来处理节点变化的回调函数。返回两个参数:
mutations
:节点变化记录列表(sequence<MutationRecord>
)observer
:构造MutationObserver 对象
。
1 | var observe = new MutationObserver(function (mutations, observer) {}); |
MutationObserver
对象有三个方法,分别如下:
observe
:设置观察目标,接受两个参数: (target
:观察目标,options
:通过对象成员来设置观察选项)disconnect
:阻止观察者观察任何改变takeRecords
:清空记录队列并返回里面的内容
关于 observe
方法中 options
参数有已下几个选项:
childList
:设置true
,表示观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化attributes
:设置true
,表示观察目标属性的改变characterData
:设置true
,表示观察目标数据的改变subtree
:设置为true
,目标以及目标的后代改变都会观察attributeOldValue
:如果属性为true
或者省略,则相当于设置为true
,表示需要记录改变前的目标属性值,设置了attributeOldValue
可以省略attributes
设置characterDataOldValue
:如果characterData
为true
或省略,则相当于设置为true
,表示需要记录改变之前的目标数据,设置了characterDataOldValue
可以省略characterData
设置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
极大地增加了灵活性,可以设置各种各样的选项来满足程序员对目标的观察。
我们简单看几个例子:
1 | <div id="target" class="block" name="target"> |
1.callback 的回调次数
1 | var target = document.getElementById('target'); |
MutationObserver
的 callback
回调函数是异步的,只有在全部 DOM
操作完成之后才会调用 callback。
2.当只设置{ childList: true}
时,表示观察目标子节点的变化
1 | var observe = new MutationObserver(function (mutations, observe) { |
如果想要观察到子节点以及后代的变化需设置{childList: true, subtree: true}
attributes
选项用来观察目标属性的变化,用法类似与 childList
,目标属性的删除添加以及修改都会被观察到。
3.我们需要注意的是 characterData
这个选项,它是用来观察 CharacterData
类型的节点的,只有在改变节点数据时才会观察到,如果你删除或者增加节点都不会进行观察,还有如果对不是 CharacterData
类型的节点的改变不会观察到,比如:
1 | observe.observe(target, { characterData: true, subtree: true }); |
我们只需要记住只有对 CharacterData
类型的节点的数据改变才会被 characterData
为 true
的选项所观察到。
4.最后关注一个特别有用的选项 attributeFilter
,这个选项主要是用来筛选要观察的属性,比如你只想观察目标 style
属性的变化,这时可以如下设置:
1 | observe.observe(target, { attributeFilter: ['style'], subtree: true }); |
disconnect
方法是用来阻止观察的,当你不再想观察目标节点的变化时可以调用 observe.disconnect()
方法来取消观察。
takeRecords
方法是用来取出记录队列中的记录。它的一个作用是,比如你对一个节点的操作你不想马上就做出反应,过段时间在显示改变了节点的内容。
1 | var observe = new MutationObserver(function () {}); |
MutationRecord
变动记录中的属性如下:
type
:如果是属性变化,返回”attributes”,如果是一个 CharacterData 节点(Text 节点、Comment 节点)变化,返回”characterData”,节点树变化返回”childList”target
:返回影响改变的节点addedNodes
:返回添加的节点列表removedNodes
:返回删除的节点列表previousSibling
:返回分别添加或删除的节点的上一个兄弟节点,否则返回 nullnextSibling
:返回分别添加或删除的节点的下一个兄弟节点,否则返回 nullattributeName
:返回已更改属性的本地名称,否则返回 nullattributeNamespace
:返回已更改属性的名称空间,否则返回 nulloldValue
:返回值取决于 type。对于”attributes”,它是更改之前的属性的值。对于”characterData”,它是改变之前节点的数据。对于”childList”,它是 null
其中 type
、target
这两个属性不管是哪种观察方式都会有返回值,其他属性返回值与观察方式有关,比如只有当 attributeOldValue
或者 characterDataOldValue
为 true
时 oldValue
才有返回值,只有改变属性时,attributeName
才有返回值等。