仕様による 、BODY
およびFRAMESET
要素のみが、アタッチする「onload」イベントを提供しますが、知りたいです動的に作成されたDOM要素がJavaScriptのDOMに追加されたとき。
私が現在使用している超ナイーブなヒューリスティックスは次のとおりです。
私が求めているのは、私が行っていることで十分であるという確認(これもIE7とFF3の両方で機能している)か、何らかの理由で完全に気づかなかったより良い解決策です。おそらく他のプロパティをチェックする必要があります。
編集:私はこれを行うためにブラウザにとらわれない方法を望んでいます、残念ながら私は1つのブラウザの世界に住んでいません。そうは言っても、ブラウザ固有の情報は高く評価されていますが、どのブラウザで動作するかが機能するかを確認してください。よろしくお願いします。
更新:これに興味がある人のために、私が最後に使用した実装は次のとおりです:
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 /
document.getElementById('newElementId');
を実行して、trueが返されるかどうかを確認できますか?そうでない場合は、あなたが言うように、100ms待ってから再試行しますか?
DOMツリーをドキュメント要素まで歩く代わりに、element.ownerDocument
を使用します。ここを参照してください: https://developer.mozilla.org/en-US/docs/DOM/Node.ownerDocument そしてこれを行います:
element.ownerDocument.body.contains(element)
あなたは元気です.
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";
});
更新
リクエストにより、私のコメントからの情報を私の投稿に追加します
今日、AjaxianのPeppyライブラリーに John Resigによるコメント があり、彼のSizzleライブラリーがDOM挿入イベントを処理できる可能性を示唆しているようです。 IEも処理するコードがあるかどうかを知りたいと思います
ポーリングのアイデアに従って、要素がドキュメントに追加されるまで一部の要素プロパティ(たとえば、element.scrollTop)が利用できないことを読みました。おそらく、すべてのDOMトラバーサルを実行する代わりに、それをポーリングできます。
最後に、IEで、探索する価値のあるアプローチの1つは、onpropertychangeイベントを試すことです。ドキュメントに追加すると、少なくとも1つのプロパティでそのイベントがトリガーされるようになります。
完璧な世界では、突然変異イベントをフックできます。標準のブラウザでも確実に機能するか疑問です。ミューテーションイベントはすでに実装されているようです。そのため、これを追加して、それらをサポートするブラウザでのタイムアウトポーリングではなく、ネイティブミューテーションイベントを使用できます。
_document.body.innerHTML
_を最後に保存された_.innerHTML
_と比較して変更を監視するDOM変更の実装を確認しました。最終的に特定のノードがまだ追加されているかどうかを確認するので、各割り込みを確認するだけの方がよいでしょう。
私が考えることができる改善は _ (コメントを参照)。またはIE以外のすべてで.offsetParent
_ではなく_.parentNode
_を使用すると、ループからいくつかの親が削除される可能性があります。compareDocumentIndex()
を使用し、__ IEのテスト_.sourceIndex
_プロパティを使用します(ノードが存在しない場合は-1でなければなりません) DOMのt)。
これも役立つかもしれません: XブラウザーのJohnDocumentによるcompareDocumentIndexの実装 。
DOMNodeInserted
イベント(またはDOMNodeInsertedIntoDocument
)が必要です。
編集:これらのイベントはIEでサポートされていない可能性がありますが、現時点ではテストできません。
A 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!
observer
イベントハンドラーは、ノードがdocument
に追加または削除されるたびにトリガーされます。次に、ハンドラー内でcontains
チェックを実行して、myElement
がdocument
にあるかどうかを判断します。
mutations
に対して直接document.contains
チェックを実行できるため、myElement
に格納されている各MutationRecordを反復処理する必要はありません。
パフォーマンスを向上させるには、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/