MutationObserver API
我最喜欢的网页技巧之一是使用CSS和JavaScript来检测DOM节点的插入和删除,祥见Detect DOM Node Insertions with JavaScript and CSS Animations。这个技巧和博文发布在我们没有适合的API来检测这样的事件的时期。现在我们有了MutationObserver,一个用于高效检测许多节点操作的API。让我们来看一下!
基本的MutationObserver API
对我来说MutationObserver API有点复杂,但下面是基本的设置:
|
|
为了使用MutationObserver需要有不少的代码,但可以分解为:
使用一个处理抛出的任何事件的callback创建
MutationObserver的一个实例为
MutationObserver创建一套设置调用
MutationObserver实例的observe方法,传入要监听的节点(和它的子节点)以及设置信息当你想停止检测的时候,调用
disconnect
MutationObserver设置
MDN提供了MutationObserver可设置项的详细信息:
childList:如果需要检测目标节点的子节点(包含文本节点)的添加和移除则设置为true。attributes:如果需要检测目标节点属性的改变则设置为true。characterData:如果需要检测目标节点data值的改变则设置为true。subtree:如果要检测的不仅是目标节点,还包含其子孙节点则设置为true。attributeOldValue:如果attributes设置为true,并且需要记录目标节点属性改变前的值,则设为true。characterDataOldValue:如果characterData设置为true,并且需要记录目标节点data改变前的值,则设为true。attributeFilter:如果不需要检测全部属性的改变,则设置为属性localName(不包含命名空间)的一个数组。
这是相当多的当监听一个节点和/或其子节点需要注意的东西。
MutationRecord:MutationObserver处理结果
当检测到一个改变时的结果对象也详细记录了:
type (String):如果是一个属性变化返回attributes,如果是一个CharacterData节点的变化返回characterData,如果是子节点的变化返回childList。target (Node):根据type返回受改变影响的节点。对于attributes,返回属性改变的节点。对于characterData,返回CharacterData节点。对于childList,返回子节点改变了的那个节点。addedNodes (NodeList):返回添加的节点。如果没有节点被添加了,则返回空的NodeList。removedNodes (NodeList):返回删除的节点。如果没有节点被删除了,则返回空的NodeList。previousSibling (Node):返回被添加或者删除节点的前一个兄弟节点,或者null。nextSibling (Node):返回被添加或者删除节点的后一个兄弟节点,或者null。attributeName (String):返回改变了的属性的localName,或者null。attributeNamespace (String):返回改变了的属性的命名空间,或者null。oldValue (String):返回值依赖于type。对于attributes,它是属性改变之前的值。对于characterData,它是节点data改变之前的值。对于childList,它是null。
好了。现在让我们看看MutationObserver的一些实际例子。
检测一个节点被添加了
我的Detect DOM Node Insertions with JavaScript and CSS Animations博文的使用场景是检测添加了新节点,因此让我们新建一个检测节点插入的代码段:
|
|
做为结果的MutationRecord显示了addedNodes: NodeList[1],这意味着一个节点被添加到了DOM数的更深层次的某个位置。type的值是childList。
检测一个节点被移除了
移除一个节点显示了如下的MutationRecord:
|
|
这个操作的type值同样是childList,但是现在removeNodes显示了NodeList[1],一个包含被移除节点的NodeList。
检测属性变化
如果一个元素的属性改变了,你将马上就知道。MutationRecord会显示:
|
|
同样注意target会指示是那个节点的属性改变了。oldValue值会显示属性的前一个值,而标准的getAttribute检查会给你新的属性值。
停止监听
如果你希望编写最高效的app,你应仅仅在你需要监听的那段时间添加监听器,并且在结束后立马移除:
|
|
MutationObserver的实例拥有一个disconnect方法用于停止监听。因为你的app可能会有非常非常多的DOM操作,你会希望拥有能力在用户与页面交互的时候停止监听。
MutationObserver API似乎有点繁琐了,但是它是相当强大的,并且提供了丰富的信息,而且是无hack的。Daniel Buchner原创的高明的“hack”提供了检测节点添加和移除兼容性更好的方式,但是如果可能应使用MutationObserver。