MutationObserver
Mutation Observer API 用來監視DOM變動。DOM的任何變動,比如節點的增刪、屬性的變動、文字內容的變化,這個API都可以得到通知。
首先這個API歸屬於微任務,也就是說是非同步的,這樣設計也是為了應付Dom變動頻繁的特點,防止頻繁變動佔用js執行棧造成頁面卡頓。比如說:如果不是非同步當DOM變動觸發觀察者的回撥函式執行,就會堵塞後續程式碼的執行;是非同步的話,在響應時間內比如說插入1000個p元素,那麼MutationObserver會把這些響應合併成一次。
MutationObserver有以下特點:
- 非同步執行
- 把非同步時間內的DOM變動記錄封裝成一個陣列處理,可以以陣列的長度判斷頁面載入何時Dom跳躍大。
- 它既可以觀察DOM的所有型別變動,也可以指定只觀察某一類型別的變動。
MutationObserver建構函式
早期的Firefox和Chrome版本中需要帶有字首。
var MutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver;
複製程式碼
首先使用MutationObserver建構函式例項化一個MutationObserver物件,同時指定這個例項的回撥函式。
const observer = new MutationObserver(()=>{})
複製程式碼
建構函式可以接受連個引數:
- 第一個引數為變動記錄資料。
- 第二個引數為觀察者例項。
const observer = new MutationObserver((mutations,observer) => {
console.log(muatation,observer);
})
複製程式碼
MutationObserver例項
建構函式呼叫MutationObserver得到MutationObserver例項。例項有以下方法。
observe
observe方法用來監聽Dom變化,接受兩個引數:
- 第一個引數是所要觀察的Dom節點
- 第二個物件是一個配置物件,指定所要觀察的變動型別
observer.observe(document.documentElement,{
})
複製程式碼
Dom的變動型別一共有三種:
- childList : 子節點變動(指新增、刪除、修改)。
- attributes :屬性的變動
- characterData : 節點內容或節點文字的變動。
當變動型別為true的時候為監聽狀態,預設為不監聽。
需要注意的是:必須同時指定三種變動型別中的一種或者多種,否則會報錯。
除了三種變動型別外,物件屬性還可以設定其他值:
- subtree : 布林值,表示是否將觀察者應用於該節點的後代所有節點。
- attributeOldValue:布林值,表示觀察attributes變動時,是否需要記錄變動前的屬性值。
- characterDataOldValue:布林值,表示觀察characterData變動時,是否需要記錄變動前的值。
- attributeFilter:陣列,表示需要觀察的特定屬性(比如說['class','src']);
observer.observe(document.documentElement,{
childList : true,
attributes : true,
characterData : true,
subtree : true,
attributeOldValue: true,
characterDataOldValue: true,
})
複製程式碼
taskRecoreds
taskRecoreds方法用於清楚變動記錄,即不再處理未處理的變動。該方法返回變動記錄的陣列。
const changes = observer.taskRecords();
console.log(changes);
複製程式碼
disconnect
disconnect方法用來停止觀察。呼叫該方法後,DOM再發生變動,也不會觸發觀察者物件。
observer.disconnect();
複製程式碼
MutationRecord物件
DOM每次發生變化,就會生成一條變動記錄(MutationRecord例項)。該例項包含了與變動相關的所有資訊。MutationObserver處理的就是一個個MutationRecord例項組成的陣列。
MutationRecord包含了Dom的有關資訊,有以下屬性:
- type:觀察變動的型別(attribute、characterData或者childList)
- target : 發生變動的DOM節點
- addedNodes :新增的DOM節點
- removedNodes : 刪除的DOM節點。
- previousSibling : 前一個同級節點,如果沒有則返回null。
- nextSibling : 下一個同級的節點,如果沒有則返回null。
- attributeName:發生變動的屬性名,如果設定了attributeFilter,則只返回attributeFilter中的屬性值。
- oldValue:這個屬性只對attribute和characterData變動生效,如果發生childList變動,則返回null。
總結
MutationObserver是非同步操作,屬於微任務,在Vue原始碼中實現nextTick
的排程機制使用到了這個。
我個人這個東西在監聽Dom變化上還是有大作用的。我們在做效能監控的時候,通常會檢測一些效能指標,例如:FP、FCP、FMP
這些效能指標。FMP
的標準定義不明確,通常是指Dom活動最大的時刻。所以說FMP
比較難檢測,通常採用body前後打mark
的方式檢測。使用這個API的話,可以檢測哪個時間段Dom到文字中最多,也就可以說成活動最大。
最後
這是Can I Use上的MutationObserver API的支援度。