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

Posted

技术标签:

【中文标题】检测节点何时被删除(或因为父节点被从 DOM 中删除)【英文标题】:Detect when a node is deleted (or removed from the DOM because a parent was) 【发布时间】:2017-12-09 16:35:19 【问题描述】:

我想检测一个节点(例如,nodeX)何时不再可用,无论是因为它被删除还是因为它的父节点(或其父节点)被删除。

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

有没有更简单的方法?


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

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

这是我试图确认或否认的。

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

【问题讨论】:

是的。我阅读了文档并尝试了似乎合理的猜测。也许有什么我错过或误解了 (注意我并不是说我提出的方法太复杂,我只是想知道有没有更直接的方法) 通过将节点存储在数组中来跟踪它们,然后使用 .map() 复制原始数组并返回修改后的数组。这样,您将拥有原始数组和一个由所有已删除节点或所有剩余节点组成的数组。 突变观察者,或重复超时检查元素(突变观察者是正确的选择,如果支持 @dandavis 突变事件已被弃用。 (developer.mozilla.org/en-US/docs/Web/Guide/Events/…) 【参考方案1】:

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

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

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

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

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

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

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

【讨论】:

【参考方案2】:

这是一个识别元素如何被删除的实现(直接删除或因为父元素被删除

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>

【讨论】:

【参考方案3】:

这已经在堆栈溢出之前被问过。 How to detect element being added/removed from dom element?

如果您只是想检查某个特定时间点是否存在某事,您显然可以执行以下操作:

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

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

【讨论】:

以上是关于检测节点何时被删除(或因为父节点被从 DOM 中删除)的主要内容,如果未能解决你的问题,请参考以下文章

如何根据子节点删除父节点和/或 css 样式

你能检测到 dom 节点的样式何时设置为“自动”吗?

DOM节点

XML DOM 节点树概述

DOM节点的删除(jQuery)

DOM技术