MutationObserver: observe() 方法

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

MutationObserverobserve() 方法用於配置 MutationObserver 的回撥,使其開始接收與給定選項匹配的 DOM 更改通知。

根據配置,觀察者可以監視 DOM 樹中的單個 Node,或者監視該節點及其部分或全部後代節點。同一個節點可以被多個觀察者監視,同一個 MutationObserver 可以透過多次呼叫 observe() 來監視 DOM 樹不同部分或不同型別的更改。

要停止 MutationObserver(使其不再觸發任何回撥),請呼叫 MutationObserver.disconnect()

語法

js
observe(target, options)

引數

目標

DOM Node(可能是 Element)在 DOM 樹中,用於監視更改,或作為要監視的節點子樹的根節點。

options

一個物件,提供描述哪些 DOM 變異應該報告給 mutationObservercallback 的選項。在呼叫 observe() 時,至少必須將 childListattributes 和/或 characterData 中的一個設定為 true。否則,將丟擲 TypeError 異常。

選項如下:

subtree 可選

設定為 true 可將監視範圍擴充套件到以 target 為根的整個節點子樹。所有其他屬性也將擴充套件到子樹中的所有節點,而不僅僅應用於 target 節點。預設值為 false。請注意,如果 target 的後代節點被移除,該後代子樹中的更改將繼續被觀察,直到關於移除本身的通知被傳遞為止。

childList 可選

設定為 true 可監視目標節點(如果 subtreetrue,則監視其後代節點)的子節點新增或現有子節點移除。預設值為 false

attributes 可選

設定為 true 可監視被監視節點上屬性值的更改。預設值為 true,如果指定了 attributeFilterattributeOldValue 中的任何一個,否則預設值為 false

attributeFilter 可選

要監視的特定屬性名稱陣列。如果未包含此屬性,則所有屬性的更改都會導致變異通知。

attributeOldValue 可選

設定為 true 可記錄監視節點屬性值更改時任何屬性的先前值;有關監視屬性更改並記錄值的示例,請參見 監視屬性值。預設值為 false

characterData 可選

設定為 true 可監視指定的節點(如果 subtreetrue,則監視其後代節點)中包含的字元資料的更改。預設值為 true,如果指定了 characterDataOldValue,否則預設值為 false

characterDataOldValue 可選

設定為 true 可記錄被監視節點文字值更改時的先前文字值。預設值為 false

返回值

無(undefined)。

異常

TypeError

在以下任何情況下丟擲

  • options 的配置導致實際上沒有任何內容被監視。(例如,如果 childListattributescharacterData 都為 false。)
  • options.attributes 的值為 false(表示不監視屬性更改),但 attributeOldValuetrue 和/或 attributeFilter 存在。
  • characterDataOldValue 選項為 truecharacterDatafalse(表示不監視字元更改)。

示例

基本用法

在此示例中,我們演示瞭如何在設定好 MutationObserver 例項後,呼叫其 observe() 方法,並傳入一個目標元素和一個 options 物件。

js
// create a new instance of `MutationObserver` named `observer`,
// passing it a callback function
const observer = new MutationObserver(() => {
  console.log("callback that runs when observer is triggered");
});

// call `observe()`, passing it the element to observe, and the options object
observer.observe(document.querySelector("#element-to-observe"), {
  subtree: true,
  childList: true,
});

使用 subtree 時移除的後代節點

如果您使用 subtree 選項監視一個節點,即使該子樹的一部分已被移除,您仍將收到該節點後代節點的更改通知。但是,一旦關於移除的通知被傳遞,該已分離子樹的進一步更改將不再觸發觀察者。

這可以防止您錯過在連線斷開後、您有機會專門開始監視已移動節點或子樹以進行更改之前發生的更改。理論上,這意味著如果您跟蹤描述發生的更改的 MutationRecord 物件,您應該能夠“撤銷”更改,將 DOM 恢復到其初始狀態。

html
<div id="target">
  <div id="child"></div>
</div>
js
const target = document.getElementById("target");
const child = document.getElementById("child");

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    console.log(mutation.type, mutation.target.id, mutation.attributeName);

    if (mutation.type === "childList" && mutation.target.id === "target") {
      // After receiving the notification that the child was removed,
      // further modifications to the detached subtree no longer trigger the observer.
      child.setAttribute("data-bar", "");
    }
  });
});

observer.observe(target, {
  attributes: true,
  childList: true,
  subtree: true,
});

target.removeChild(child);
// This change happens before the "childList target" notification is delivered,
// so it will also trigger the observer.
child.setAttribute("data-foo", "");

// Output:
// childList target null
// attributes child data-foo
// There is no "attributes child data-bar" notification.

使用 attributeFilter

在此示例中,設定了一個 Mutation Observer 來監視顯示聊天室使用者名稱稱的子樹中任何元素的 statususername 屬性的更改。例如,這可以讓程式碼反映使用者暱稱的更改,或將其標記為離開鍵盤 (AFK) 或離線。

js
function callback(mutationList) {
  mutationList.forEach((mutation) => {
    switch (mutation.type) {
      case "attributes":
        switch (mutation.attributeName) {
          case "status":
            userStatusChanged(mutation.target.username, mutation.target.status);
            break;
          case "username":
            usernameChanged(mutation.oldValue, mutation.target.username);
            break;
        }
        break;
    }
  });
}

const userListElement = document.querySelector("#user-list");

const observer = new MutationObserver(callback);
observer.observe(userListElement, {
  attributeFilter: ["status", "username"],
  attributeOldValue: true,
  subtree: true,
});

監視屬性值

在此示例中,我們監視一個元素以獲取屬性值更改,並新增一個按鈕,在元素的 dir 屬性("ltr""rtl")之間進行切換。在觀察者的回撥函式中,我們記錄了屬性的舊值。

HTML

html
<button id="toggle">Toggle direction</button><br />
<div id="container">
  <input type="text" id="rhubarb" dir="ltr" value="Tofu" />
</div>
<pre id="output"></pre>

CSS

css
body {
  background-color: paleturquoise;
}

button,
input,
pre {
  margin: 0.5rem;
}

JavaScript

js
const toggle = document.querySelector("#toggle");
const rhubarb = document.querySelector("#rhubarb");
const observerTarget = document.querySelector("#container");
const output = document.querySelector("#output");

toggle.addEventListener("click", () => {
  rhubarb.dir = rhubarb.dir === "ltr" ? "rtl" : "ltr";
});

const config = {
  subtree: true,
  attributeOldValue: true,
};

const callback = (mutationList) => {
  for (const mutation of mutationList) {
    if (mutation.type === "attributes") {
      output.textContent = `The ${mutation.attributeName} attribute was modified from "${mutation.oldValue}".`;
    }
  }
};

const observer = new MutationObserver(callback);
observer.observe(observerTarget, config);

結果

規範

規範
DOM
# ref-for-dom-mutationobserver-observe②

瀏覽器相容性