[英]How can I determine if a dynamically-created DOM element has been added to the DOM?
根據規范 ,只有BODY
和FRAMESET
元素提供附加的“onload”事件,但我想知道在JavaScript中將動態創建的DOM元素添加到DOM中的時間。
我目前正在使用的超級天真的啟發式方法如下:
我所追求的是確認我正在做的事情是足夠的(再次,它在IE7和FF3中工作)或更好的解決方案,無論出於何種原因,我完全忘記了; 也許我應該檢查其他屬性等。
編輯:我想要一個與瀏覽器無關的方法,不幸的是,我並不住在一個瀏覽器的世界里; 也就是說,瀏覽器特定的信息是值得贊賞的,但是請注意哪個瀏覽器知道它確實有效。謝謝!
更新:對於任何對它感興趣的人,這是我最終使用的實現:
function isInDOMTree(node) {
// If the farthest-back ancestor of our node has a "body"
// property (that node would be the document itself),
// we assume it is in the page's DOM tree.
return !!(findUltimateAncestor(node).body);
}
function findUltimateAncestor(node) {
// Walk up the DOM tree until we are at the top (parentNode
// will return null at that point).
// NOTE: this will return the same node that was passed in
// if it has no ancestors.
var ancestor = node;
while(ancestor.parentNode) {
ancestor = ancestor.parentNode;
}
return ancestor;
}
我想要的原因是提供一種合成DOM元素的onload
事件的方法。 這是該函數(雖然我使用的東西略有不同,因為我與MochiKit一起使用它):
function executeOnLoad(node, func) {
// This function will check, every tenth of a second, to see if
// our element is a part of the DOM tree - as soon as we know
// that it is, we execute the provided function.
if(isInDOMTree(node)) {
func();
} else {
setTimeout(function() { executeOnLoad(node, func); }, 100);
}
}
例如,此設置可以按如下方式使用:
var mySpan = document.createElement("span");
mySpan.innerHTML = "Hello world!";
executeOnLoad(mySpan, function(node) {
alert('Added to DOM tree. ' + node.innerHTML);
});
// now, at some point later in code, this
// node would be appended to the document
document.body.appendChild(mySpan);
// sometime after this is executed, but no more than 100 ms after,
// the anonymous function I passed to executeOnLoad() would execute
希望對某人有用。
注意:我最終得到這個解決方案而不是Darryl的答案的原因是因為getElementById技術只有在同一個文檔中才有效。 我在頁面上有一些iframe,頁面之間以某些復雜的方式進行通信 - 當我嘗試這個時,問題是它無法找到元素,因為它是一個不同的文檔的一部分而不是它執行的代碼。
最直接的答案是使用Chrome,Firefox(Gecko),Internet Explorer,Opera和Safari支持的Node.contains
方法。 這是一個例子:
var el = document.createElement("div");
console.log(document.body.contains(el)); // false
document.body.appendChild(el);
console.log(document.body.contains(el)); // true
document.body.removeChild(el);
console.log(document.body.contains(el)); // false
理想情況下,我們會使用document.contains(el)
,但這在IE中不起作用,因此我們使用document.body.contains(el)
。
不幸的是,您仍然需要輪詢,但檢查元素是否在文檔中卻非常簡單:
setTimeout(function test() {
if (document.body.contains(node)) {
func();
} else {
setTimeout(test, 50);
}
}, 50);
如果您可以在頁面中添加一些CSS,那么這是另一種使用動畫檢測節點插入的聰明技術: http : //www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/
而不是將DOM樹移動到文檔元素,只需使用element.ownerDocument
。 請參閱此處: https : //developer.mozilla.org/en-US/docs/DOM/Node.ownerDocument並執行以下操作:
element.ownerDocument.body.contains(element)
而且你很好。
你能不做一個document.getElementById('newElementId');
並查看是否返回true。 如果沒有,就像你說的那樣,等待100毫秒再試一次?
您可以查詢document.getElementsByTagName(“*”)。length或創建一個自定義的appendChild函數,如下所示:
var append = function(parent, child, onAppend) {
parent.appendChild(child);
if (onAppend) onAppend(child);
}
//inserts a div into body and adds the class "created" upon insertion
append(document.body, document.createElement("div"), function(el) {
el.className = "created";
});
更新
根據要求,將我的評論中的信息添加到我的帖子中
John Resig今天在Ajaxian的Peppy庫上發表評論似乎表明他的Sizzle庫可能能夠處理DOM插入事件。 我很想知道是否會有代碼來處理IE
根據輪詢的想法,我已經讀過在元素被附加到文檔之前一些元素屬性不可用(例如element.scrollTop),也許你可以輪詢它而不是進行所有的DOM遍歷。
最后一件事:在IE中,一種可能值得探索的方法是使用onpropertychange事件。 我估計將其附加到文檔必然會觸發至少一個屬性的事件。
在完美的世界中,您可以勾選突變事件。 我懷疑他們即使在標准瀏覽器上也能可靠地工作。 聽起來你已經實現了一個變異事件,所以你可以添加它來使用本機變異事件,而不是在支持它們的瀏覽器上進行超時輪詢。
我已經看到DOM-change實現通過將document.body.innerHTML
與上次保存的.innerHTML
進行比較來監視更改,這不是很優雅(但是很有效)。 由於您最終將檢查是否已添加特定節點,因此您最好只檢查每個中斷。
我能想到的改進是 使用 (看評論)。 或者在除IE之外的所有IE上使用.offsetParent
而不是.parentNode
因為它可能會將一些父.parentNode
從循環中刪除 compareDocumentIndex()
並測試IE的.sourceIndex
(如果節點不在DOM中,則應為-1)。
這也可能有所幫助: John Resig的X瀏覽器compareDocumentIndex實現 。
您需要DOMNodeInserted
事件(或DOMNodeInsertedIntoDocument
)。
編輯:完全有可能IE不支持這些事件,但我現在無法測試。
您應該使用MutationObserver來檢測何時將元素添加到DOM。 現在,MutationObservers在所有現代瀏覽器(Chrome 26 +,Firefox 14 +,IE11,Edge,Opera 15+等)中得到廣泛支持。
下面是一個簡單的示例,說明如何在將元素添加到DOM時使用MutationObserver
進行偵聽。
為簡潔起見,我使用jQuery語法構建節點並將其插入DOM。
var myElement = $("<div>hello world</div>")[0];
var observer = new MutationObserver(function(mutations) {
if (document.contains(myElement)) {
console.log("It's in the DOM!");
observer.disconnect();
}
});
observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
$("body").append(myElement); // console.log: It's in the DOM!
只要在document
添加或刪除任何節點, observer
事件處理程序就會觸發。 在處理程序內部,我們然后執行contains
檢查以確定myElement
現在是否在document
。
您不需要遍歷存儲在mutations
每個MutationRecord,因為您可以直接在myElement
執行document.contains
檢查。
要提高性能,請將document
替換為DOM中包含myElement
的特定元素。
var finalElement=null;
我在循環中構建dom對象,當循環在最后一個循環中並且創建lastDomObject
:
finalElement=lastDomObject;
離開循環:
while (!finalElement) { } //this is the delay...
下一個操作可以使用任何新創建的dom對象。 它是第一次嘗試。
這是從jQuery代碼中提取的問題的另一種解決方案。 以下函數可用於檢查節點是否連接到DOM或是否“斷開連接”。
function isDisconnected( node ) { return !node || !node.parentNode || node.parentNode.nodeType === 11; }
nodeType === 11定義DOCUMENT_FRAGMENT_NODE,它是未連接到文檔對象的節點。
有關詳細信息,請參閱John Resig撰寫的以下文章: http : //ejohn.org/blog/dom-documentfragments/
IE中不支持DOMNodeInserted或DOMNodeInsertedIntoDocument事件。 來自IE [IE]功能的另一個缺點是compareDocumentPosition函數,它的設計符合其名稱的建議。
至於建議的解決方案,我認為沒有更好的解決方案(除非你做一些骯臟的技巧,如覆蓋原生DOM成員實現)
此外,更正問題的標題:動態創建的元素從創建時起就是DOM的一部分,它可以附加到文檔片段或另一個元素,但它可能不會附加到文檔。
我還認為你描述的問題不是你所遇到的問題,這個問題對你來說是一個潛在的解決方案。 您可以詳細解釋一下用例嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.