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②

浏览器兼容性