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();