删除元素后的MutationObserver行为

时间:2016-02-07 12:38:43

标签: javascript mutation-observers

我有MutationObserver绑定到#foo html元素。

var target = document.querySelector("#foo");
var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        // ...
    });
});

当用户点击#button元素时,#foo会被删除,并在一秒后再次显示。

<div id="button">Click me to remove the Foo!</div>
<div id="foo">Hello, I'm Foo!</div>

正如我注意到的那样,在#foo被移除并重新创建后,观察者停止了工作。

  • 这是正常行为吗?
  • 那么,我需要再次启动观察者吗?

第三个问题:

  • 第一个观察者是否完全被移除?或者,而不是那样,它仍在运行,只是&#34;什么都不做&#34;? - 我是在问这个问题,因为如果只有其中一个人在做真正的工作,我不想让多个观察者参与其中。

1 个答案:

答案 0 :(得分:7)

  

并在第二次

之后再次出现

这种行为完全取决于你的意思。

如果您的意思是创建了具有相同id元素,那么是,这是预期的行为:当您在元素上调用observer.observe时,您就是&#39 ;在特定元素上调用它,而不是与其ID匹配的任何元素。如果从DOM中删除该元素并将其替换为另一个看起来相同的元素,则观察者不会神奇地连接到该新的不同元素:

&#13;
&#13;
var target = document.querySelector("#foo");
var observer = new MutationObserver(function(mutations) {
    snippet.log("#foo was modified");
});
observer.observe(target, {subTree: true, childList: true});
var counter = 0;
tick();
setTimeout(function() {
  snippet.log("Replacing foo with a new one");
  target.parentNode.removeChild(target);
  target = document.createElement("div");
  target.id = "foo";
  target.innerHTML = "This is the new foo";
  document.body.insertBefore(target, document.body.firstChild);
}, 1000);
function tick() {
  target.appendChild(document.createTextNode("."));
  if (++counter < 20) {
    setTimeout(tick, 200);
  }
}
&#13;
<div id="foo">This is the original foo</div>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
&#13;
&#13;
&#13;

如果您的意思是将相同的元素重新放回DOM,那么不,这不是预期的行为,而不是在此示例中发生的事情:

&#13;
&#13;
var target = document.querySelector("#foo");
var observer = new MutationObserver(function(mutations) {
    snippet.log("#foo was modified");
});
observer.observe(target, {subTree: true, childList: true});
var counter = 0;
tick();
setTimeout(function() {
  snippet.log("Removing foo for a moment");
  target.parentNode.removeChild(target);
  setTimeout(function() {
    snippet.log("Putting the same foo back in");
    document.body.insertBefore(target, document.body.firstChild);
  }, 100);
}, 1000);
function tick() {
  target.appendChild(document.createTextNode("."));
  if (++counter < 20) {
    setTimeout(tick, 200);
  }
}
&#13;
<div id="foo">This is the original foo</div>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
&#13;
&#13;
&#13;

这里的关键外卖消息是观察者正在观察传递给observe一个特定元素

这些问题仅适用于您删除旧元素并将其替换为全新元素的情况:

  

那么,我需要再次启动观察者吗?

如果您要删除原始元素并在其中放置一个新元素,您应该告诉观察者停止观察:

observer.disconnect();

获得新元素后,您可以将观察者连接到它:

observer.observe(theNewElement, /*...options go here...*/);
  

第一个观察者是否完全被移除?或者说,它仍在运行,只是&#34;什么都不做&#34;?

理论中,由于the spec清楚表明它是引用其观察者的元素,因此如果你释放对该元素的唯一引用,那么理论上观察者因为元素及其观察者列表被清理而断开连接。但是,如果没有观察者对元素的引用,观察者的disconnect方法如何实现则不清楚,因此它们可能具有相互引用。如果你保留对观察者的引用,那将保持内存中的相互引用。我确实故意断开它。

  

我问这个问题,因为我不想让多个观察者跑,如果只有其中一个人在做真正的工作。

观察员不要跑步,&#34;他们做出反应。观察者将继续观察原始元素,直到/除非您断开连接。如果你没有对原始元素做任何事情,那么观察者除了占用内存之外不会做任何其他事情。但同样,如果您要删除元素,则应断开观察者的连接。