如何检测DOM元素中的添加或删除的元素?

80

假设我有一个div#parent元素,我使用jQuery向其中添加和删除元素。那么,我如何检测到这样的事件在div#parent元素上发生了呢?


5个回答

157

不要使用DOM节点插入和删除等变异事件。

相反,使用DOM Mutation Observers,它们在除IE10及以下版本外的所有现代浏览器中都得到支持(Can I use)。变异观察器旨在取代变异事件(已被弃用),因为发现其设计存在缺陷,导致性能较低。

var x = new MutationObserver(function (e) {
  if (e[0].removedNodes) console.log(1);
});

x.observe(document.getElementById('parent'), { childList: true });

15
谢谢您的提问。但是Mutation Observers存在缺陷:我想将观察者设置为稍后将附加到树中的节点,但我不知道其父节点(如果使用'DOMNodeRemoved',我将知道父节点)。您有什么想法吗?我希望节点能够监听自身的销毁。 - DenisKolodin
1
@DenisKolodin 哇,我没有注意到这个评论,抱歉。为了后人的利益,应该回答这个问题。它确实意味着在文档级别上放置一个事件,但是突变事件有如此巨大的性能惩罚,以至于可能并不重要。 - Qantas 94 Heavy
2
不确定是否值得在您的答案中提及,因为它并没有直接回答这个问题,但自定义元素具有disconnectedCallback。 - Mr5o1
@Qantas94Heavy 你的意思是什么?如果性能惩罚是真实存在的,为什么我们建议不使用DOMNodeRemoved?我也在考虑在文档级别上使用一个。请查看https://stackoverflow.com/questions/69426920/javascript-mutationobserver-observing-a-child-element-after-observing-a-parent - mjs
@mmm 正如 Mr5o1 所指出的,您可以使用自定义元素。如果您无法这样做,您可以将其绑定到父级并在更改时重新绑定:https://dev59.com/ZVUL5IYBdhLWcg3waXYr - Qantas 94 Heavy
显示剩余3条评论

41

按照@Qantas在他的答案中提到的建议,您可以使用Mutation Observers


以下方法已经被弃用

您可以使用DOMNodeInsertedDOMNodeRemoved

$("#parent").on('DOMNodeInserted', function(e) {
    console.log(e.target, ' was inserted');
});

$("#parent").on('DOMNodeRemoved', function(e) {
    console.log(e.target, ' was removed');
});

MDN文档


19
变异事件已弃用,因此这个答案不再正确。变异观察器被设计为取代变异事件,所以Qantas的答案是正确的。有关详细信息,请参阅以下链接:https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events 和 https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver - Parziphal
使用此方法,但仅使用配置来监听子DOM更新, 参考:https://academy.byidmore.com/post/Listen-Added-and-Deleted-Node-in-HTML-DOM-5be15ad61bde484c8fbedd35 - yussan
这可能会很慢,而且在生产代码中可能不是一个好主意,但这似乎是唯一同步工作的方法(不像MutationObserver)。当没有其他合适的选项时,例如尝试找到更改DOM的代码行时,这是调试的好选择。 - CertainPerformance
@satpal,是否有可能将它们合并在一起,而不是有两组代码?如果是 DOMNodeInsertedDOMNodeRemoved,则执行函数 {} - wharfdale
如果性能惩罚是真实存在的,为什么我们被建议远离DOMNodeRemoved?我也在考虑在文档级别上进行观察。请参见https://stackoverflow.com/questions/69426920/javascript-mutationobserver-observing-a-child-element-after-observing-a-parent - mjs

3

我无法在顶部答案下面发表评论,但是为了回答你的问题@DenisKolodin,为了监听自毁,您可以这样做:

function watchElForDeletion(elToWatch, callback, parent = document.querySelector('body')){
  const observer = new MutationObserver(function (mutations) {

    // loop through all mutations
    mutations.forEach(function (mutation) {

        // check for changes to the child list
        if (mutation.type === 'childList') {

            // check if anything was removed and if the specific element we were looking for was removed
            if (mutation.removedNodes.length > 0 && mutation.removedNodes[0] === elToWatch) {
                callback();
            }
        }
    });
  });

  // start observing the parent - defaults to document body
  observer.observe(parent, { childList: true });
};

默认情况下,父元素为body元素,并且仅在删除您要查找的特定元素时运行回调函数。


这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Ethan McTague

3
你应该绑定DOMSubtreeModified事件。
$("#parent").bind("DOMSubtreeModified",function(){
  console.log('changed');
});

http://jsfiddle.net/WQeM3/


3
“DOMSubtreeModified”事件已经被弃用:Can I Use - Cody
1
如果性能惩罚是真的,为什么我们被建议不使用DOMNodeRemoved?我也在考虑文档级别的一个。请参见https://stackoverflow.com/questions/69426920/javascript-mutationobserver-observing-a-child-element-after-observing-a-parent - mjs

-5

我认为我们可以使用socket.io!

因为我们需要检测应该添加哪个元素,然后可能猜测哪个元素将被移除。

也许这是可能的。

谢谢。


是的,也许它能工作,但如何检测它呢? - R sukumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接