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

时间:2018-05-17 12:24:08

标签: javascript html html5 dom mutation-observers

我有这些:

element

我希望在从DOM中删除element.onRemove(() => releaseKraken(element)) 时调用该函数。

我可以想象这样的事情:

MutationObserver

我知道我需要MutationObserver,但我发现的所有文档都专注于观看给定元素的孩子,而我需要观察元素本身。

UPD:问题How to detect element being added/removed from dom element? 侧重于观看特定父母的孩子。我不想看孩子或父母。我希望在从DOM中删除给定元素时收到通知。不是它的孩子。而且我不想在给定元素的父母身上设置观察者(除非这是唯一的选择),因为它会对性能产生影响。

UPD2:如果我在document上设置takePersistableUriPermission(),这将导致每个会话触发数千甚至数百万次回调,并且每次回调都必须过滤掉一个巨大的回调已删除元素的列表,以查看它是否包含有问题的元素。那太疯狂了。

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

3 个答案:

答案 0 :(得分:3)

正如您所说,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,
  });
}

然后使用您的示例而不是

element.onRemove(() => releaseKraken(element));

你可以做到

onRemove(element, () => releaseKraken(element));

如果您所做的只是观看单个元素,这种方法应该足够快。虽然它似乎是一个相当数量的循环,但removedNodes很少有一个以上的节点,除非有什么东西同时消除了大量的兄弟姐妹,mutations将是相当的小的。

你也可以考虑做

callback(el);

允许你做

onRemove(element, releaseKraken);

答案 1 :(得分:1)

loganfsmyth的出色解决方案的另一种较短版本:

function makeObject<K extends PropertyKey, V>(key: K, value: V) {
   return { [key]: value } as { [P in K]: V };
}
const obj = makeObject("name", "Tom"); // {name: string}

用法相同:

printf()

答案 2 :(得分:0)

以下是我在this

上找到的解决方案

&#13;
&#13;
document.getElementById("delete_one_div").addEventListener('click', function() {
  var divToDelete = document.getElementsByTagName("div")[0];
  divToDelete.parentNode.removeChild(divToDelete);
});

var element = document.getElementById("div_to_be_watched")
var in_dom = document.body.contains(element);
var observer = new MutationObserver(function(mutations) {
  if (in_dom && !document.body.contains(element)) {
    console.log("I was just removed");
    in_dom = false;
    observer.disconnect();
  }

});
observer.observe(document.body, { childList: true });
&#13;
<div id="test">Test</div>
<div id="div_to_be_watched">Div to be watched</div>
<div class="div_to_be_watched">Second test</div>
<button id="delete_one_div">Delete one div</button>
&#13;
&#13;
&#13;

修改

我编辑了一下片段。您有两种选择:

  1. 按照原样使用它。并且它不是非常消耗内存,因为if条件并不真正复杂(仅检查主体是否包含元素)并且它仅观察到移除时刻然后停止,
  2. 让观察者只观察特定元素以限制事件触发器。