1つの要素が別の要素内に含まれているかどうかをJavaScriptでチェックインする方法


202

あるDOM要素が別のDOM要素の子であるかどうかを確認するにはどうすればよいですか?このための組み込みメソッドはありますか?たとえば、次のようなものです。

if (element1.hasDescendant(element2)) 

または

if (element2.hasParent(element1)) 

そうでない場合、これを行う方法はありますか?また、クロスブラウザである必要があります。また、子は親の下の多くのレベルにネストできることにも言及する必要があります。



私は、JSが今日「ライブ標準」であるため、受け入れられた回答を再確認して、「conatins」メソッドを受け入れられた回答として示す必要があると思います。
DavidTaubmann 2016年

回答:


219

更新:これを実現するためのネイティブな方法があります。Node.contains()。コメントと以下の回答にも記載されています。

古い答え:

parentNodeプロパティを使用して動作するはずです。また、クロスブラウザの観点からもかなり安全です。関係が1レベル深いことがわかっている場合は、次のように簡単に確認できます。

if (element2.parentNode == element1) { ... }

子を親の内側の任意の深さにネストできる場合は、次のような関数を使用して関係をテストできます。

function isDescendant(parent, child) {
     var node = child.parentNode;
     while (node != null) {
         if (node == parent) {
             return true;
         }
         node = node.parentNode;
     }
     return false;
}

お返事ありがとうございます。問題は、子が親の下の多くのレベルにネストされる可能性があることです。
AJ。

@AJ:答えを更新して、子を親の任意の深さにネストするために機能するソリューションを含めました。
2010

228
誰かがこれに今来ている場合は、最新のブラウザのネイティブ関数であるNode.contains(developer.mozilla.org/en-US/docs/DOM/Node.contains)を使用できる可能性があります。
アダム・ヒース

2
@JohnCarrellがありますNode.contains(ただし、カヌースのページはありません)
gcampbell

3
@Asaph新しい回答を含めるように回答を更新していただけませNode.containsんか?:)

355

Node.contains標準になり、すべてのブラウザで使用できるようになったため、を使用する必要があります。

https://developer.mozilla.org/en-US/docs/Web/API/Node.contains


Node.hasParent(parent)メソッドは不要ですが、Node.prototype.hasParent = function(element){return element.contains(this);};になります。
llange 14

6
モバイルブラウザーでもサポートされていますか?mdn docsには、Android、Safari、IE、およびOperaに疑問符が付いています。
thetallweeks 2014

1
@thetallweeks-少なくとも私のAndroid 7で動作します。
Sphinxxx

5
あなたは少なくとも例を追加することができます
NinoŠkopac18年

2
これは良い答えですが、例は本当にいいでしょう:var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
baron_bartek

45

私は「私のもの」を共有しなければなりませんでした。

概念的に同じもののアサフの答え(同じクロスブラウザの互換性の恩恵を受けて、でもIE6)、それはたくさん小さく、サイズが貴重であるとき、および/またはそれはそう頻繁に必要とされていない場合に便利です。

function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
  while((c=c.parentNode)&&c!==p); 
  return !!c; 
}

..またはワンライナーとして(ちょうど64文字!):

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

ここjsfiddle


使用法:
childOf(child, parent)ブール値を返しますtruefalse

説明:
while while条件がに評価される限り評価しtrueます。(AND)演算子は、このブール真/偽のを返した後、左側と右側を評価するが、唯一の場合は左側は本当でした
&&left-hand && right-hand

左側(&&)は次のとおり(c=c.parentNode)です。
これは最初にparentNodeof cを割り当て、c次にAND演算子は結果cをブール値として評価します。
以来parentNode戻ってnull親がない場合は、左とnullに変換されfalse、whileループが正しくもう親が存在しないときに停止します。

(の&&)右側は:c!==pです。比較演算子は「ではない正確に等しいです」。したがって、子の親が(指定した)親ではない場合はと評価されますが、子の親親である場合はと評価されます。 したがって falseと評価された場合、演算子はwhile条件として戻り、whileループが停止します。(while-bodyの必要はなく、閉じるセミコロンが必要です。)
!==truefalse
c!==p&&false;

したがって、whileループが終了するときは、親が見つかったときのcノード(ではないnull)か、それとも(nullループが一致を見つけずに最後まで実行されたとき)のいずれかです。

したがって、我々は単にreturn事実と(代わりノード、ブール値として換算)は:return !!c;!NOTオペレータ)(ブール値を反転trueなるfalseとその逆)。
!c変換cブールの(ノードまたはNULL)がその値を反転させることができる前に。第二の追加だから!!!c)この偽変換背中をtrueには(ダブルが理由である!!ことが多い「ブール値に変換何か」に使用されています)。


追加:
関数の本体/ペイロードが非常に小さいため、場合によっては(頻繁に使用されず、コード内で1回だけ表示される場合など)、関数を省略(ラッピング)して、whileループを使用することできます。

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

c=a; while((c=c.parentNode)&&c!==b); //c=!!c;

if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
    //do stuff
}

の代わりに:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

c=childOf(a, b);    

if(c){ 
    //do stuff
}

4
@SolomonUcko:厳密な等価比較(!==)は、緩やかな等価比較で発生する型チェックとオプションの暗黙的な変換ステップをスキップできることをコンパイラーに明らかにすることで速度を向上させ、速度を向上させます(これにより、発生したい、それはプログラマにとっても有益です)。また、私がこれを書いたときから、緩やかな比較(!=)は非常にエラーが発生しやすいか、一部の古いブラウザーではまったく機能しなかったことを思い出しているようです(IE6にあると思われますが、忘れていました) )。
GitaarLAB 2016年

29

言及されなかった別のソリューション:

ここの例

var parent = document.querySelector('.parent');

if (parent.querySelector('.child') !== null) {
    // .. it's a child
}

要素が直接の子であるかどうかは関係ありません。どの深さでも機能します。


または、.contains()メソッドを使用します

ここの例

var parent = document.querySelector('.parent'),
    child = document.querySelector('.child');

if (parent.contains(child)) {
    // .. it's a child
}

19

見てみましょうノード#compareDocumentPositionを

function isDescendant(ancestor,descendant){
    return ancestor.compareDocumentPosition(descendant) & 
        Node.DOCUMENT_POSITION_CONTAINS;
}

function isAncestor(descendant,ancestor){
    return descendant.compareDocumentPosition(ancestor) & 
        Node.DOCUMENT_POSITION_CONTAINED_BY;
}

その他の関係には、、、DOCUMENT_POSITION_DISCONNECTEDDOCUMENT_POSITION_PRECEDINGありDOCUMENT_POSITION_FOLLOWINGます。

IE <= 8ではサポートされていません。


面白い!これは、2003年に開発したJS関数を思い出します...数日かけてJS開発者の助けを借りました...信じられないほど(そして悲しいことに)、現在、完全なドラッグドロップもオブジェクトフィットの完全なブラウザー実装もありません。 。
DavidTaubmann、2016年


2

ある要素が別の要素の子であるかどうかを確認するための素晴らしいコードに出会いました。IEは.contains要素メソッドをサポートしていないため、これを使用する必要があります。これが他の人にも役立つことを願っています。

以下は関数です:

function isChildOf(childObject, containerObject) {
  var returnValue = false;
  var currentObject;

  if (typeof containerObject === 'string') {
    containerObject = document.getElementById(containerObject);
  }
  if (typeof childObject === 'string') {
    childObject = document.getElementById(childObject);
  }

  currentObject = childObject.parentNode;

  while (currentObject !== undefined) {
    if (currentObject === document.body) {
      break;
    }

    if (currentObject.id == containerObject.id) {
      returnValue = true;
      break;
    }

    // Move up the hierarchy
    currentObject = currentObject.parentNode;
  }

  return returnValue;
}

文字通り.containsを含むこのページの他のすべてのポリフィルを試しましたが、これが機能した唯一のものです。ありがとう!
protoEvangelion

1

これを試してください:

x = document.getElementById("td35");
if (x.childElementCount > 0) {
    x = document.getElementById("LastRow");
    x.style.display = "block";
}
else {
    x = document.getElementById("LastRow");
    x.style.display = "none";
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.