MutationObserver - 監聽你的 DOM 是否有變動

語言: CN / TW / HK

theme: devui-blue

持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第11天,點選檢視活動詳情

MutationObserver 可用來監視 DOM 的變化,算是一個比較老的 API,但是卻鮮為人知,他的前身是 MutationEvent:一系列監聽 DOM 變更的 event 事件 - DOMAttrModifiedDOMNodeInsertedDOMSubtreeModified 等。

個人能想到的使用場景一個是監聽 DOM 的變化,防止使用者篡改 DOM 結構,比如可以在被篡改後直接 document.write('請勿篡改') 來避免使用者篡改重要頁面並進行截圖作秀。又或者是使用 contenteditable 時監聽內容變更,在富文字編輯器領域可能會有所應用。還可以監聽一些瀏覽器外掛修改 DOM 節點的行為。

用法

與其它 Observer 類似,使用 MutationObserver 首先需要例項化一個 observer,然後呼叫它的 observe 來監聽目標元素:

js const observer = new MutationObserver((mutationList, observer) => { mutationList.forEach(mutation => { console.log(mutation); }); }); observer.observe(target, { attributes: true, childList: true, subtree: true });

https://code.juejin.cn/pen/7151992112123215886

這裡 observe 一定要通過傳入 options 明確傳入需要監聽的改動型別等引數,其中要 childListattributescharacterData 至少一個為 true

  • childList: 表明是否監聽子元素的增刪
  • attributes: 表明是否監聽屬性的變動
  • attributesFilter: 用來宣告需要監聽的屬性名稱,如果傳入了則 attributes 預設為 true
  • attributeOldValue: 設定為 true 後可以在 mutation 資訊中拿到 attribute 變動前的值
  • characterData: 表明是否需要監聽字元資料的變化,可以理解為文字節點的變化,注意新增刪除文字節點觸發的是 childList,只有改的時候才會觸發 characterData 變化
  • characterDataOldValue: 同 attributeOldValue 類似,設定為 true 後可以在 mutation 資訊中拿到 characterData 變化前的值
  • subtreesubtree 比較特殊,表示是否需要監聽子元素的變動,子元素監聽選項將會從此處 option 繼承

回撥中接受兩個引數:mutationList 為變動的 mutation 事件列表,observer 還是老樣子,上面 observer 例項的一個引用。

mutation 中欄位較多,可以從中直接獲得 DOM 變更的細節:

  • type: 標識本次變動的型別,包含三種類型,同上面 option 中的三種監聽型別:
    • attributes 表示 dom 的屬性變動
    • characterData 表示文字節點的變動
    • childList 表示其它的 node 節點變動
  • target: 當前 mutation 影響的 DOM 節點,三種類型下有些許區別:
    • attributes 類為屬性變化的元素
    • characterData 類則為變動的文字節點
    • childList 類為變動的 child 的父元素
  • addedNodes: 為新增的節點
  • removedNodes: 為刪除的節點
  • previousSibling: 刪除或新增的節點的前一個兄弟節點
  • nextSibling: 刪除或新增的節點的後一個兄弟節點
  • attributeName: 變動的屬性名稱
  • attributeNamespace: 變動的屬性的 namespace,很少用到
  • oldValue: 變動前的屬性,內容視型別和配置中的 oldValue 相關配置決定

需要注意,mutationList 是所有改動事件的合集,比如一次性改動 n 個屬性,將會生成 nmutation

其它 API

同樣除了 observe 外,MutationObserver 也提供了 disconnect 來取消所有監聽,但是居然沒有提供 unobserveemm

observer 還提供了 takeRecords,用來獲取所有已經發生的改動但是卻還沒進入回撥處理的事件,一般用於在 disconnect 前處理還未被處理的改動。

總結

MutationObserver 在日常使用中場景非常少見,然而在特定場景下可以發揮出強大的作用。