Поведение mutationobserver'а после того, как элемент был удален


У меня есть MutationObserver привязанный к элементу html #foo.

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 был удален и воссоздан, наблюдатель перестал работать.
  • это нормальное поведение?
  • Итак, мне нужно снова запустить наблюдателя?

И третий вопрос:

  • является ли первый наблюдатель полностью удаленным? Или, вместо этого, он все еще бежит, просто "ничего не делая"? - Я спрашиваю об этом, потому что не хочу, чтобы несколько наблюдателей бежали, если только один из них делает реальную работу.
1 4

1 ответ:

И появляется снова через секунду

Поведение будет полностью зависеть от того, что вы подразумеваете под этим.

Если вы имеете в видуновый элемент с тем же id создается, то да, это ожидаемое поведение: когда вы вызываете observer.observe на элемент, вы вызываете его наэтот конкретный элемент , а не любой элемент, соответствующий его ID. Если вы удалите этот элемент из DOM и замените его другим, другим элементом, который выглядит одинаково, наблюдатель будет не магически подключенный к этому новому, отличному элементу:

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);
  }
}
<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>

Если вы имеете в виду, что вы возвращаете тот же элемент обратно в DOM, то нет, это не будет ожидаемым поведением, а не тем, что происходит в этом примере:

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);
  }
}
<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>
Ключевое сообщение здесь заключается в том, что наблюдатель наблюдает за одним конкретным элементом, который вы передаете в observe.

Эти вопросы применимы только в том случае, если вы удаление старого элемента и замена его на совершенно новый:

Итак, мне нужно снова запустить наблюдателя?

Если вы удаляете исходный элемент и ставите на его место Новый, вы должны сказать наблюдателю, чтобы он прекратил наблюдение:
observer.disconnect();
Если у вас есть новый элемент, вы можете подключить к нему наблюдателя:
observer.observe(theNewElement, /*...options go here...*/);

Является ли первый наблюдатель полностью удаленным? Или, вместо этого, он все еще работает, просто " делая ничего"?

В теории , так как спецификация ясно показывает, что это элемент, который имеет ссылку на своих наблюдателей, то если вы отпустите свою единственную ссылку на элемент, в теории наблюдатель отключается, потому что элемент и его список наблюдателей очищаются. Однако неясно, как метод наблюдателя disconnect может быть реализован без того, чтобы у наблюдателя была ссылка на элемент, поэтому они могут иметь взаимные ссылки. Если ты продолжишь ваша ссылка на наблюдателя, которая сохранит взаимные ссылки в памяти. Я бы отключил его специально, чтобы быть уверенным.

Я спрашиваю об этом, потому что не хочу, чтобы несколько наблюдателей бежали, если только один из них делает реальную работу.

Наблюдатели не "бегут", они реагировать. Наблюдатель будет продолжать наблюдать исходный элемент до тех пор, пока вы не отключите его. Если вы ничего не делаете с исходным элементом, наблюдатель ничего не делает. ничего другого, чем принимать до памяти. Но опять же, если вы собираетесь удалить элемент, вы должны отключить наблюдателя.