https://msdn.microsoft.com/zh-cn/library/ie/dn265032(v=vs.85).aspx
将突变事件和属性更改事件迁移到突变观察者
Internet Explorer 11 中的突变观察者提供了对突变事件支持的所有相同方案的快速执行替换,以及对属性更改事件支持的方案的替换。
你可以使用突变事件和/或属性更改事件迁移现有代码,以使用突变观察者。
监视 DOM 突变的传统技术
Mutation events 在 Web 平台中扮演了关键角色。这些事件允许 Web 应用同步监视对网页的文档对象模型 (DOM) 中元素的动态更改。虽然突变事件很有用,但是我们也知道,由于它们的同步本质和运行它们的事件体系结构,它们会导致应用性能下降。
属性更改事件提供与突变事件相似的行为。属性更改事件也会导致性能下降,因为它们需要传统浏览器事件系统才能正常工作。
标识突变事件
突变事件最早在 Internet Explorer 9 中开始提供,可根据其名称轻松识别出来,其名称是一个字符串参数,传递到addEventListener 或 removeEventListener 平台 API:
- DOMNodeInserted
- DOMNodeRemoved
- DOMSubtreeModified
- DOMAttrModified
- DOMCharacterDataModified
下面的示例展示了其中一个突变事件在 JavaScript 代码中为何种形式:
someElement.addEventListener("DOMAttrModified", function() { //... }, false);
DOMNodeInserted、DOMNodeRemoved 和 DOMSubtreeModified 突变事件监视元素子项的结构更改—向元素子项添加了元素或者删除了元素子项。DOMSubtreeModified 事件适用于这二者:删除或添加都会触发该事件。但是,它不包含关于触发原因的任何信息(你无法单独根据该事件来区分进行的是添加更改还是删除更改)。
DOMAttrModified 突变事件报告对元素的属性列表的更改。此单一事件包括与插入、删除或更改属性相关的信息。
DOMCharacterDataModified 突变事件报告对元素的文本内容的更改。文本内容组合成称作“文本节点”的逻辑单元,仅对现有文本节点的修改会触发 DOMCharacterDataModified 事件。如果插入/创建新的文本节点,则反而会将这些节点报告为 DOMNodeInserted 事件。
在代码中应当很容易就能找到突变事件,类似于在你常用的编辑器中使用“在文件中查找...”搜索功能一样。请记住,在addEventListener 方法中经常使用变量,因此请确保首先搜索突变事件字符串(“DOMNodeInserted”、“DOMNodeRemoved”等)的使用,然后仔细检查出现的所有 addEventListener 以确保将它们全部找出。
标识属性更改事件
可以通过与传统 attachEvent 或 detachEvent IE-only 事件注册 API 一起使用的 onpropertychange 事件名称标识属性更改事件。搜索出现的所有 attachEvent 并检查 onpropertychange 的第一个参数以在你的代码中找到这些使用情况。
属性更改事件在 DOM 元素的属性更改时触发。该事件不执行冒泡操作,自 Internet Explorer 9 开始已被弃用,以支持 W3C 标准“addEventListener”事件模型。该事件包括在事件 propertyName getter 中更改的属性的名称。遗憾的是,为了分派属性更改事件,同时还会计算很多其他事件属性,其中有些事件属性会强制布局引擎重新进行计算,从而导致使用这些事件的所有应用程序产生大量性能成本。
Unlike with mutation events,属性更改事件不会整齐映射到突变观察者。但是,如果感兴趣的属性名称反映在 HTML 属性中,就有可能使用突变观察者替换属性更改事件的使用。例如,id - 反映 id 属性;style.color - 反映在序列化的“style”属性中;className - 与 class 属性对应。
突变观察者有何不同
突变观察者不是基于 Web 平台的事件模型。这是一个重用区别,这使它们能够更快地进行分派,而无需在 DOM 元素层次结构中对事件执行冒泡操作。
而且,突变观察者的目标是在通知你的观察者之前记录多项更改。它们批量提供突变记录,以避免在你的应用中滥发此类事件。相比之下,突变事件是同步发送的,可以中断正常的代码执行来通知你应用发生突变。尽管突变观察者采用延迟的通知模型,但仍可保证你的应用的观察者可以在下一个重画之前收到(并有机会处理)所有突变记录。
这两项更改会影响你的应用必须如何调整来支持突变观察者。
突变观察者注册
必须首先创建突变观察者,然后才能在指定元素上注册它们。要创建突变观察者,请使用 JavaScript new 运算符并指定回调方法:
var mutationObserver = new MutationObserver(callback);
你提供给突变观察者构造函数的回调将不同于你可能对当前突变事件事件使用的回调。下面将进行详细说明。
创建观察者后,现在你指示它观察特定元素。通常,这与你之前在其上注册突变事件的元素相同:
mutationObserver.observe(someElement, options);
如果你未保存对该元素的引用,则突变观察者实例将由 Web 平台保留在内存中(只要它正在观察至少一个元素)。如果你未保存对观察者的引用,仍可以通过观察者的回调引用它(它将是回调范围中的 this 对象,也是回调函数的第二个参数)。
选项参数是一个简单的 JavaScript 对象,具有你必须提供的用来精确描述要观察何种突变的属性。属性选项与之前提到的突变的三个类别相对应:
- childList
- 属性
- characterData
childList 选项的值为 true 时,意味着“观察到对此元素的子元素的更改”(既包括删除也包括添加)。此选项包括作为此元素的子项添加或删除的文本节点。
attribute 选项的值为 true 时,意味着“观察到对此元素的属性的更改”(既包括删除也包括添加和更改)。
characterData 选项为 true 时,意味着“观察到对此元素的文本节点的更改”(对文本节点值的更改,不包括将文本节点整个删除或全新添加时的情况)。
第四个选项“subtree”也很重要。前三个选项(默认)只孤立观察其目标元素,而不考虑它的任何后代(其子树)。要监视指定元素及其所有后代,请将“subtree”属性设置为 true。由于突变事件具有在 DOM 中冒泡的特征,所以需要使用“subtree”选项来维持与在上级元素上注册的突变事件的均衡。
下表描述了突变观察者选项与突变事件名称之间的对应关系:
突变事件 | 突变观察者选项 | 注意 |
---|---|---|
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 } |
最后,还有几个选项用于保存属性和字符数据更改的上一个值,以及用于优化对观察有重要意义的属性的范围:
- attributeOldValue 和 characterDataOldValue 选项的值为 true 时,会在发生属性或 characterData 更改时保存上一个值。
- attributeFilter 选项具有属性名称的字符串数组,将观察限定在指定的属性范围内。此选项仅在 attributes 选项设置为 true 时有意义。
利用此信息,以前针对突变事件注册的任何代码都可以替换为针对突变观察者注册的代码:
// Watch for all changes to the body element's children document.body.addEventListener("DOMNodeInserted", nodeAddedCallback, false); document.body.addEventListener("DOMNodeRemoved", nodeRemovedCallback, false);
现在成为:
// Watch for all changes to the body element's children new MutationObserver(nodesAddedAndRemovedCallback).observe(document.body, { childList: true, subtree: true });
突变观察者回调
使用两个参数调用突变观察者回调函数:
- 记录列表
- 对正在调用回调的突变观察者对象的引用
如果你正在对突变观察者重用突变事件回调,请小心。当发生相关突变时,MutationObserver 将在 MutationRecord对象中记录你请求的更改信息并调用你的回调函数,但直到当前范围内的所有脚本都运行之后才会进行此记录和调用。自上次调用回调后,有可能发生多个突变(每一个突变由单个 MutationRecord 表示)。
“记录”参数是一个 JavaScript 数组,由 MutationRecord 对象组成。该数组中的每个对象都代表在观察的元素上发生的一个突变。
记录具有下列属性:
MutationRecord 属性 | 说明 |
---|---|
此记录所记录的突变的类型。可能值:attributes、characterData、childList。 |
|
在其上记录突变的元素。类似于 event.target 或 event.srcElement。 |
|
作为此突变的一部分添加或删除的一组节点;仅在 type 是 childList 时才有意义。这些数组可以为空。 |
|
添加或删除的节点的上一个或下一个同辈;仅在 type 是 childList 时才有意义。这些值可以为 null。 |
|
已添加、删除或更改的属性的名称和命名空间。如果记录类型不是“属性”,值将为 null。 |
|
该属性的上一个值始终为 characterData。如果突变观察选项不包括attributeOldValue 或 characterDataOldValue 标志,或者 type 是childList,则该值可能为 null。 |