检测给定元素已从DOM中删除而不牺牲性能

And*_*aus 3 html javascript html5 dom mutation-observers

我有这些:

const element = this.getElementById("victim")

function releaseKraken(targetElement) {}
Run Code Online (Sandbox Code Playgroud)

我希望element从DOM中删除该函数。

我可以想象这样的事情:

element.onRemove(() => releaseKraken(element))
Run Code Online (Sandbox Code Playgroud)

我知道我需要MutationObserver,但是我发现的所有文档都集中在观察给定元素的孩子,而我需要观察元素本身。

UPD:问题如何检测从dom元素添加/删除的元素? 专注于观察给定父母的孩子。我不想看孩子或父母。我想从DOM中删除给定元素时收到通知。不是孩子。而且我不想在给定元素的父对象上设置观察者(除非这是唯一的选择),因为这会影响性能。

UPD2:如果我将MutationObserveron 设置为on document,这将导致每个会话触发该回调数千次甚至数百万次,并且每次回调都必须过滤大量已删除元素以查看其是否包含有问题的元素。那太疯狂了。

我需要像上面显示的简单的东西。我希望回调仅被触发一次:给定元素被删除时。

log*_*yth 5

如您所说,MutationObserver仅允许您检测何时操纵元素的子代。这意味着您需要聆听父级并检查所做的更改,以查看目标元素是否已删除。

function onRemove(element, callback) {
  const parent = element.parentNode;
  if (!parent) throw new Error("The node must already be attached");

  const obs = new MutationObserver(mutations => {
    for (const mutation of mutations) {
      for (const el of mutation.removedNodes) {
        if (el === element) {
          obs.disconnect();
          callback();
        }
      }
    }
  });
  obs.observe(parent, {
    childList: true,
  });
}
Run Code Online (Sandbox Code Playgroud)

然后用你的例子代替

element.onRemove(() => releaseKraken(element));
Run Code Online (Sandbox Code Playgroud)

你可以做

onRemove(element, () => releaseKraken(element));
Run Code Online (Sandbox Code Playgroud)

如果您正在做的只是观看单个元素,则此方法应该足够快。尽管看起来像是一个不错的循环,但是removedNodes要不止一个节点是非常罕见的,除非某个东西能够一次全部清除大量兄弟姐妹,否则它也将mutations非常小。

您也可以考虑做

callback(el);
Run Code Online (Sandbox Code Playgroud)

这会让你做

onRemove(element, releaseKraken);
Run Code Online (Sandbox Code Playgroud)

  • 嘿,@loganfsmyth!我们遇到了此解决方案的问题。问题是,当删除一个节点时,只有该节点及其子节点不会出现在“removedNodes”中。由于任何给定元素的父元素都可以被删除,所以我们需要像“$(givenElement).parents().toArray().includes(removedNode)”这样的东西,而不是“if (el === element)”。另外,我们必须监视“document”而不是直接父级,并将“subtree: true”包含到“observe()”选项中。 (2认同)

joe*_*joe 5

loganfsmyth 优秀解决方案的替代、较短版本:

function onRemove(el, callback) {
  new MutationObserver((mutations, observer) => {
    if(!document.body.contains(el)) {
      observer.disconnect();
      callback();
    }
  }).observe(document.body, { childList: true });
}
Run Code Online (Sandbox Code Playgroud)

用法是一样的:

onRemove(myElement, function() {
  console.log("The element was removed!");
})
Run Code Online (Sandbox Code Playgroud)