javascript DOMNode从文档中删除的简单变异观察者版本

6rqinv9w  于 2022-12-25  发布在  Java
关注(0)|答案(2)|浏览(124)

我为DOM元素附加了一些功能,并希望在从DOM中删除元素时能够清除所有引用,以便可以对其进行垃圾收集,
我最初检测元素移除的版本是这样的:

var onremove = function(element, callback) {
    var destroy = function() {
        callback();
        element.removeEventListener('DOMNodeRemovedFromDocument', destroy);
     };
     element.addEventListener('DOMNodeRemovedFromDocument', destroy);
};

然后我读到mutation eventsMutationObserver取代了,所以我试着移植我的代码,这是我得到的结果:

var isDescendant = function(desc, root) {
     return !!desc && (desc === root || isDecendant(desc.parentNode, root));
 };

var onremove = function(element, callback) {
    var observer = new MutationObserver(function(mutations) {
        _.forEach(mutations, function(mutation) {
            _.forEach(mutation.removedNodes, function(removed) {
                if (isDescendant(element, removed)) {
                    callback();

                    // allow garbage collection
                    observer.disconnect();
                    observer = undefined;
                }
            });
        });
    });
    observer.observe(document, {
         childList: true,
         subtree: true
    });
};

这在我看来过于复杂(而且效率不是很高)。我是错过了什么还是这真的是应该的工作方式?

agxfikkp

agxfikkp1#

其实...是的,有一个更优雅的解决方案:)。
您添加的内容看起来不错,而且似乎经过了很好的优化。然而,有一种更简单的方法可以知道节点是否附加到DOM。

function onRemove(element, onDetachCallback) {
    const observer = new MutationObserver(function () {
        function isDetached(el) {
            if (el.parentNode === document) {
                return false;
            } else if (el.parentNode === null) {
                return true;
            } else {
                return isDetached(el.parentNode);
            }
        }

        if (isDetached(element)) {
            observer.disconnect();
            onDetachCallback();
        }
    })

    observer.observe(document, {
         childList: true,
         subtree: true
    });
}
p5cysglq

p5cysglq2#

在我看来,这个公认的答案是不可接受的,因为递归在不必要的时候是不好的,而且removednodes列表上的.contains()比遍历整个dom更快。或者,你可以定义一个自定义事件,并将其应用于任何你想监视其删除的元素,这里有一个使用变异观察器创建自定义“removed”事件的例子。

const removedEvent = new Event("removed");
const observer = new MutationObserver(function (mutations) {
    mutations.forEach(function(mutation){mutation.removedNodes.forEach(function(node){node.dispatchEvent(removedEvent);})});
});
observer.observe(document.documentElement,{childList:true,subtree:true});

//Usage example:
let element = document.getElementById("anyelement");
//The custom event "removed" listener can be added before or after the element is added to the dom
element.addEventListener("removed",function(){
    console.info("Element removed from DOM."); //Do whatever you need for cleaning up but don't disconnect the observer if you have other elements you need to react to the removal of.
});

相关问题