Определить, когда узел удален (или удален из DOM, потому что родитель был)
Я хочу определить, когда узел (скажем, nodeX) больше не доступен, либо потому, что он был удален, либо потому, что его родитель (или родительский родитель) был удален.
Пока что все, о чем я могу думать, это использовать Mutation Observer, чтобы увидеть любые удаления на странице, и проверить, был ли удаленный узел nodeX или имел узел X для потомка.
Есть ли более простой способ?
Обратите внимание: насколько я понимаю, связанный вопрос (что этот вопрос "является дубликатом") спрашивает "как я могу обнаружить [прямое] удаление узла". Мой спрашивает: "Как я могу обнаружить удаление узла или его родителя (или любого другого предка)".
Насколько я понимаю, с наблюдателями мутаций это не так просто: вам нужно проверить каждый удаленный узел, чтобы узнать, был ли он предком.
Это то, что я пытаюсь подтвердить или опровергнуть.
Насколько я понимаю, это отличается от связанного вопроса.
3 ответа
Вот реализация, которая идентифицирует, как элемент был удален (напрямую или потому, что родитель был удален)
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>
Принятый ответ потерпит неудачу, если удаленное поддерево будет видоизменено после удаления из документа. Например:
target.parent.remove();
target.remove();
сгенерирует один вызов для наблюдателя мутации для удаления родительского узла (удаление целевого узла не будет сообщено наблюдателю, как это произошло, когда поддерево уже было удалено из документа).
var parentMatch = nodes.some(parent => parent.contains(target));
в принятом ответе вернется ложь, так как целью больше не является ребенок. Проблема в том, что отчеты о событиях мутации пакетируются, и вы не можете полагаться на состояние во время удаления узла, оставаясь таким же, как и во время вызова вашего наблюдателя мутации.
По этой причине, столкнувшись с такой же проблемой, как вопросник, я создал WeakSet предков целевого узла. Используя наблюдателя мутаций, прикрепленного к корню документа, я сравнил мутации с этим набором и целью. Если событие удаления узла мутации включает узел в этом наборе или целевой узел, я знаю, что целевой узел был удален из дерева. Это не означает, что узел все еще удален (возможно, он был добавлен обратно) или что узел все еще является потомком предков в моем наборе. Но я могу быть уверен, что узел был удален в прошлом.
Вы должны быть осторожны, чтобы различать состояние DOM в момент после мутации и состояние в момент получения события мутации.
Это было задано ранее при переполнении стека. Как обнаружить добавление / удаление элемента из элемента dom?
Если вы просто хотите проверить, существует ли что-то в определенный момент времени, вы, очевидно, можете сделать что-то вроде:
if (!document.querySelector(".nonexistent")) {
console.log("doesn't exist");
}
В противном случае наблюдатели мутаций - ваш единственный выбор.