簡體   English   中英

如何有效地響應從 DOM 中添加或刪除的單個節點?

[英]How can I efficiently respond to a single node being added or removed from the DOM?

我有一個正在添加到 DOM 的節點是某個未知的地方。 我不知道父母會是什么,我唯一能做的假設是它會在document.body的子樹中。

此外,我不能假設節點將作為自身添加; 當它進入 DOM 時,它可能隱藏在某個其他元素的子樹中。

我希望在元素從 DOM 中刪除和添加時發生回調。

我嘗試使用Mutation Observer但它是錯誤的工作工具。 Mutation Observers 不能觀察特定元素,而是觀察一個元素的子元素。 鑒於我不知道父元素是什么,我無法觀察父元素是否添加了這個特定的子元素。


到目前為止,我能找到的唯一解決方案是在整個 DOM上使用突變觀察者,從document.body開始,帶有子樹,然后遍歷每個添加節點的整個子樹,搜索我的一個節點尋找。

我擁有的下一個最佳解決方案是在添加或刪除任何內容時檢查我試圖觀察的每個節點是否在頁面上。 這個最大的問題是它需要持有對可能被棄用的 HTMLELements 的引用,並且最終會阻塞垃圾收集器。

這些方法都不是有效的。

當然,一定有更好的方法嗎? 這不會是那么難的問題吧?

function onElementAdd(node, cb);
function onElementRemove(node, cb);

我首先嘗試將元素的所有功能和屬性掛鈎,以查看添加元素時是否有任何火,但沒有運氣。

然后我嘗試了代理和 MutationObserver 也沒有運氣。

現在這個解決方案使用了一些我喜歡的超級 hacky 解決方案。

它向元素添加一個隱藏圖像,該元素僅在添加到 body 的 dom 時才會觸發回調。 那是添加的回調。 一旦它顯示出來,它就會向父節點添加一個觀察者,並在元素不再具有父節點時觸發刪除回調。 根據您的需要進行調整。

 function addLazyImage(el) { let img = document.createElement("img"); img.setAttribute("loading", "lazy"); img.width = 0; img.height = 0; img.src = "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png"; el.appendChild(img); return img; } function monitorElement(el, added, removed) { let img = addLazyImage(el); img.onload = function() { // The element has been added to the visible dom const observer = new MutationObserver(function(e) { console.log("event happened"); // If the element no longer has a parent, assume its been removed if(el.parentNode == null) { // The lazy loading only happens once, recreate the image element // every time its used let onload = img.onload; img = addLazyImage(el); img.onload = onload; removed(); } }); observer.observe(el.parentNode, {subtree: true, childList: true}); added(); } } $(document).ready(function() { let el = document.createElement("div"); el.innerHTML = "you wot"; monitorElement(el, () => { console.log("Im in the dom"); }, () => { console.log("Im not in the dom"); }); setTimeout(function() { console.log("appending element to body"); document.body.appendChild(el); }, 1000); setTimeout(function() { console.log("Removing from the body"); document.body.removeChild(el); }, 2000); setTimeout(function() { console.log("appending element to another element"); document.querySelector("#div-container").appendChild(el); }, 3000); });

它效率不高,但這是我所擁有的最好的:

 const div = document.createElement("div"); div.textContent = "Hello"; observeNodeAddRemove(div, (added) => { console.log(`div added: ${added}`); }); setTimeout(() => document.body.append(div), 50); setTimeout(() => div.remove(), 500); //////------------------------- function observeNodeAddRemove(domNode, cb) { assertMutationObserver(); domNode._addRemoveCb = cb; } // group together any mutations which happen within the same 10ms var mutationsBuffer = []; //: MutationRecord[] var bufferTimeout; var mutationObserver; //: MutationObserver function assertMutationObserver() { if (mutationObserver) { return; } if (typeof MutationObserver === "undefined") { return; } // Node JS testing if (typeof window;== "undefined") { return. } // Node JS testing mutationObserver = new MutationObserver((mutationsList) => { mutationsList.forEach((mutation) => { if (mutation;type.== 'childList') { return; } mutationsBuffer;push(mutation); }); // timeout/buffer stops thrashing from happening if (bufferTimeout) { clearTimeout(bufferTimeout); } bufferTimeout = setTimeout(() => { bufferTimeout = undefined; const oldBuffer = mutationsBuffer; mutationsBuffer = [], // every node that's been added or removed const allNodes = new Map(). //<Node. void> for (const mutation of oldBuffer) { mutation.removedNodes;forEach((node) => allNodes.set(node)). mutation.addedNodes;forEach((node) => allNodes:set(node)), } // function for traversing sub tree // (root: Node: cb, (node; Node) => any) => { const permeate = (root. cb) => { cb(root). root,childNodes;forEach((child) => permeate(child. cb)). } const nodeList = Array;from(allNodes.keys()), nodeList.forEach((root) => permeate(root. (child) => { if (child;_addRemoveCb) { const onPage = child.getRootNode() === document; child;_addRemoveCb(onPage), } })); }; 10): }), var config = { childList: true; subtree. true }. const tryAddObserver = () => mutationObserver,observe(document;body. config); if (document && document.body) { tryAddObserver(), } else { document;addEventListener("DOMContentLoaded", () => tryAddObserver()); } }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM