web-dev-qa-db-ja.com

動的に作成されたDOM要素がDOMに追加されたかどうかを確認するにはどうすればよいですか?

仕様によるBODYおよびFRAMESET要素のみが、アタッチする「onload」イベントを提供しますが、知りたいです動的に作成されたDOM要素がJavaScriptのDOMに追加されたとき。

私が現在使用している超ナイーブなヒューリスティックスは次のとおりです。

  • 最終的な祖先が見つかるまで要素のparentNodeプロパティをトラバースします(つまり、parentNodeがnullになるまでparentNode.parentNode.parentNode.etc)。

  • 最終的な祖先にnull以外の定義済みのbodyプロパティがある場合

    • 問題の要素がdomの一部であると仮定する
  • else

    • これらの手順を100ミリ秒で繰り返します

私が求めているのは、私が行っていることで十分であるという確認(これもIE7とFF3の両方で機能している)か、何らかの理由で完全に気づかなかったより良い解決策です。おそらく他のプロパティをチェックする必要があります。


編集:私はこれを行うためにブラウザにとらわれない方法を望んでいます、残念ながら私は1つのブラウザの世界に住んでいません。そうは言っても、ブラウザ固有の情報は高く評価されていますが、どのブラウザで動作するかが機能するかを確認してください。よろしくお願いします。

40
Jason Bunting

更新:これに興味がある人のために、私が最後に使用した実装は次のとおりです:

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があり、ページがいくつかの複雑な方法で相互に通信している-これを試したところ、要素が実行されているコードとは異なるドキュメントの一部であるため、要素が見つからないという問題がありました。 。

28
Jason Bunting

最も簡単な答えは、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 /

21
Chris Calo

document.getElementById('newElementId');を実行して、trueが返されるかどうかを確認できますか?そうでない場合は、あなたが言うように、100ms待ってから再試行しますか?

8
Darryl Hein

DOMツリーをドキュメント要素まで歩く代わりに、element.ownerDocumentを使用します。ここを参照してください: https://developer.mozilla.org/en-US/docs/DOM/Node.ownerDocument そしてこれを行います:

element.ownerDocument.body.contains(element)

あなたは元気です.

8
ydaniv

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つのプロパティでそのイベントがトリガーされるようになります。

2
Leo

完璧な世界では、突然変異イベントをフックできます。標準のブラウザでも確実に機能するか疑問です。ミューテーションイベントはすでに実装されているようです。そのため、これを追加して、それらをサポートするブラウザでのタイムアウトポーリングではなく、ネイティブミューテーションイベントを使用できます。

_document.body.innerHTML_を最後に保存された_.innerHTML_と比較して変更を監視するDOM変更の実装を確認しました。最終的に特定のノードがまだ追加されているかどうかを確認するので、各割り込みを確認するだけの方がよいでしょう。

私が考えることができる改善は _.offsetParent_ではなく_.parentNode_を使用すると、ループからいくつかの親が削除される可能性があります。 (コメントを参照)。またはIE以外のすべてでcompareDocumentIndex()を使用し、__ IEのテスト_.sourceIndex_プロパティを使用します(ノードが存在しない場合は-1でなければなりません) DOMのt)。

これも役立つかもしれません: XブラウザーのJohnDocumentによるcompareDocumentIndexの実装

2
Borgar

DOMNodeInsertedイベント(またはDOMNodeInsertedIntoDocument)が必要です。

編集:これらのイベントはIEでサポートされていない可能性がありますが、現時点ではテストできません。

1
eyelidlessness

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チェックを実行して、myElementdocumentにあるかどうかを判断します。

mutationsに対して直接document.containsチェックを実行できるため、myElementに格納されている各MutationRecordを反復処理する必要はありません。

パフォーマンスを向上させるには、documentをDOMのmyElementを含む特定の要素に置き換えます。

1
Elliot B.
var finalElement=null; 

ループでdomオブジェクトを構築しています。ループが最後のサイクルにあり、lastDomObjectが作成されると、次のようになります。

 finalElement=lastDomObject; 

ループを離れる:

while (!finalElement) { } //this is the delay... 

次のアクションでは、新しく作成されたdomオブジェクトを使用できます。それは最初の試みでうまくいきました。

0
user1403517

これは、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/

0
nik