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。 |