Detect when a node is deleted (or removed from the DOM because a parent was)

北战南征 提交于 2020-06-12 04:52:26

问题


I want to detect when a node (nodeX, say) is no longer available, either because it was deleted or because its parent (or its parents parent) was deleted.

So far, all I can think of is to use Mutation Observer to see any deletions on the page, and check if the deleted nodes was nodeX or had nodeX for a descendant.

Is there an easier way?


Please note: as far as I understand, the linked question (that this question "is a duplicate of") asks "how can I detect a [direct] deletion of a node". Mine asks "How can I detect the deletion of a node or its parent (or any other ancestor)".

As far as I understand, this is not straightforward with mutation observers: You need to check every deleted node to see if it was an ancestor.

This is what I seek to confirm or deny.

As far as I understand, that is different from the linked question.


回答1:


Here is an implementation that identifies how the element was removed (either directly or because a parent was removed)

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>



回答2:


The accepted answer will fail if the removed subtree is mutated after removal from the document. For example:

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

will generate one call to the mutation observer for the parent node removal (the target node removal will not be reported to the observer as it happened when the subtree was already removed from the document).

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

in the accepted answer will return false as the target is no longer a child. The problem is that mutation event reporting is batched and you cannot rely on state at the time of node removal staying the same as at the time of the call to your mutation observer.

For this reason, facing a similar issue as the questioner, I created a WeakSet of target node ancestors. Using a mutation observer attached to the document root, I compared mutations against this set and the target. If a mutation node removal event includes a node in this set or the target node, I know the target node was removed from the tree. That doesn't imply the node is still removed (it may have been added back) or that the node is still a child of the ancestors in my set. But I can be sure that the node was removed in the past.

You have to be careful to differentiate DOM state at the moment after a mutation and the state at the time you receive the mutation event.




回答3:


This has been asked before on stack overflow. How to detect element being added/removed from dom element?

If you just want to check whether something exists at a particular point in time, you could obviously do something like:

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

Otherwise Mutation Observers are your only option.



来源:https://stackoverflow.com/questions/44935865/detect-when-a-node-is-deleted-or-removed-from-the-dom-because-a-parent-was

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!