检测节点何时被删除(或因为父节点被删除而从 DOM 中删除)

问题描述 投票:0回答:4

我想检测节点(例如nodeX)何时不再可用,要么是因为它被删除了,要么是因为它的父节点(或其父节点)被删除了。

到目前为止,我能想到的就是使用Mutation Observer来查看页面上的任何删除,并检查删除的节点是否是nodeX或有nodeX作为后代。

有更简单的方法吗?


请注意:据我了解,链接的问题(该问题“是重复的”)询问“如何检测节点的[直接]删除”。我的问题是“如何检测节点或其父节点(或任何其他祖先)的删除”。

据我了解,这对于突变观察者来说并不简单:您需要检查每个删除的节点以查看它是否是祖先。

这是我想要确认或否认的。

据我了解,这与链接的问题不同。

javascript dom dom-events mutation-observers
4个回答
14
投票

这是一个实现,用于标识元素如何被删除(直接删除或因为父元素被删除

var target = document.querySelector('#to-be-removed');

var observer = new MutationObserver(function(mutations) {
  // check for removed target
  mutations.forEach(function(mutation) {
    var nodes = Array.from(mutation.removedNodes);
    var directMatch = nodes.indexOf(target) > -1
    var parentMatch = nodes.some(parent => parent.contains(target));
    if (directMatch) {
      console.log('node', target, 'was directly removed!');
    } else if (parentMatch) {
      console.log('node', target, 'was removed through a removed parent!');
    }

  });
});

var config = {
  subtree: true,
  childList: true
};
observer.observe(document.body, config);


var qs = document.querySelector.bind(document);
qs('#ul').addEventListener('click', function(){qs('ul').remove();}, false)
qs('#li').addEventListener('click', function(){qs('#to-be-removed').remove();}, false)
<ul>
  <li>list item 1</li>
  <li>list item 2</li>
  <li id="to-be-removed">list item 3</li>
  <li>list item 4</li>
</ul>

<button id="ul">remove ul</button>
<button id="li">remove li</button>


6
投票

如果删除的子树在从文档中删除后发生变异,则接受的答案将失败。例如:

target.parent.remove();
target.remove();

将生成对突变观察者的一次调用,以删除父节点(目标节点删除不会报告给观察者,因为它发生在子树已从文档中删除时)。

var parentMatch = nodes.some(parent => parent.contains(target));

在接受的答案中将返回 false,因为目标不再是孩子。问题在于突变事件报告是批量的,您不能依赖节点删除时的状态与调用突变观察者时保持相同。

出于这个原因,面对与提问者类似的问题,我创建了一个目标节点祖先的WeakSet。使用附加到文档根的突变观察器,我将突变与该集和目标进行了比较。如果突变节点删除事件包括该集合中的节点或目标节点,我知道目标节点已从树中删除。这并不意味着该节点仍然被删除(它可能已被添加回来)或者该节点仍然是我的集合中祖先的子节点。但我可以确定该节点过去已被删除。

您必须小心区分突变后此刻的 DOM 状态和收到突变事件时的状态。


1
投票

之前在堆栈溢出时已经问过这个问题。 如何检测dom元素中添加/删除的元素?

如果你只是想检查某个特定时间点是否存在某些东西,你显然可以这样做:

if (!document.querySelector(".nonexistent")) {
  console.log("doesn't exist");
}

否则突变观察者是你唯一的选择。


0
投票

实际上有一个有趣的解决方法。以下是我们需要满足的一些假设:

  1. 我们有我们想要监视的节点的引用。
  2. 我们只想检测该特定节点。

使用requestAnimationFrame,检查节点是否连接。

let watchAbleNode = document.getElementById("el");

let callback = () => {
  if ( watchAbleNode != null ) {
    if ( !watchAbleNode.isConnected() ) {
      //useful stuff you need to do
      watchAbleNode = null; //to garbage collect
    }
  }
  window.requestAnimationFrame(callback)
}

callback()
© www.soinside.com 2019 - 2024. All rights reserved.