web-dev-qa-db-fra.com

Comment vérifier en Javascript si un élément est contenu dans un autre

Comment vérifier si un élément du DOM est l'enfant d'un autre élément du DOM? Existe-t-il des méthodes intégrées pour cela? Par exemple, quelque chose comme:

if (element1.hasDescendant(element2)) 

ou

if (element2.hasParent(element1)) 

Si non alors des idées comment faire cela? Il doit également être cross browser. Je devrais également mentionner que l'enfant pourrait être imbriqué de nombreux niveaux en dessous du parent.

172
AJ.

L'utilisation de la propriété parentNode devrait fonctionner. C'est également assez sûr d'un point de vue multi-navigateur. Si la relation est connue pour être d'un niveau, vous pouvez la vérifier simplement:

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

Si l'enfant peut être imbriqué de manière arbitraire au plus profond du parent, vous pouvez utiliser une fonction semblable à celle-ci pour tester la relation:

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

Vous devez utiliser Node.contains, car il est maintenant standard et disponible dans tous les navigateurs.

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

306
Brian Di Palma

Je devais juste partager le "mien".

Bien que conceptuellement identique à réponse d'Asaph (bénéficiant de la même compatibilité entre navigateurs, même IE6), il s'agit d'un lot ​​plus petit et qui s'avère pratique lorsque la taille est réduite. et/ou quand on n'en a pas besoin si souvent.

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

..ou comme une ligne (seulement 64 caractères!):

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

et jsfiddle here .


sage:
childOf(child, parent) renvoie le booléen true | false.

Explication:
while est évalué tant que la condition while est évaluée à true.
L'opérateur && (AND) renvoie ce booléen true/false after en évaluant les côtés gauche et droit, mais uniquement if le côté gauche était vrai (left-hand && right-hand).

Le côté gauche (de &&) est: (c=c.parentNode).
Ceci affectera d'abord la parentNode de c à c, puis l'opérateur AND évaluera la c résultante comme un booléen.
Puisque parentNode retourne null s'il n'y a plus de parent et que null est converti en false, la boucle while s'arrête correctement lorsqu'il n'y a plus de Parents.

Le côté droit (de &&) est: c!==p.
L'opérateur de comparaison !== est 'not ​​exactement égal à'. Ainsi, si le parent de l'enfant n'est pas le parent (spécifié), il est évalué à true, mais si le parent de l'enfant est ​​le parent, il est évalué à false.
Donc ifc!==p est évalué à false, puis l'opérateur && renvoie false sous la forme de la condition while et de la boucle while. (Notez qu’il n’est pas nécessaire de disposer d’un while-body et que le point-virgule ; de clôture est requis.)

Ainsi, lorsque la boucle while se termine, c est un noeud (et non null) lorsqu'il trouve un parent OR, il s’agit de null (lorsque la boucle est exécutée). à la fin sans trouver un match).

Ainsi, nous avons simplement return ce fait (converti en valeur booléenne au lieu du nœud) avec: return !!c;: l'opérateur ! (NOT opérateur) inverse une valeur booléenne (true devient false et vice-versa).
!c convertit c (nœud ou null) en un booléen avant qu'il ne puisse inverser cette valeur. Donc, ajouter un second ! (!!c) convertit ce faux back en true (raison pour laquelle un double !! est souvent utilisé pour "convertir n'importe quoi en booléen" ).


Extra:
Le corps/la charge de la fonction est si petit que, selon les cas (comme quand elle n’est pas souvent utilisée et n’apparaît qu’une seule fois dans le code), on pourrait ​​omettre même la fonction ) et utilisez simplement la boucle 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
}

au lieu de:

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
}
41
GitaarLAB

Une autre solution qui n'a pas été mentionnée:

Exemple ici

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

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

Peu importe que l'élément soit un enfant direct, cela fonctionnera à n'importe quelle profondeur.


Vous pouvez également utiliser la méthode .contains() :

Exemple ici

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

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

Regardez Node # 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;
}

Les autres relations incluent DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_PRECEDING et DOCUMENT_POSITION_FOLLOWING.

Non pris en charge dans IE <= 8.

18
user663031

Vous pouvez utiliser la méthode includes

var result = parent.contains(child);

ou vous pouvez essayer d'utiliser compareDocumentPosition ()

var result = nodeA.compareDocumentPosition(nodeB);

Le dernier est plus puissant: il renvoie un masque de bits.

13
Iegor Kozakov

Je suis tombé sur un morceau de code merveilleux pour vérifier si un élément est un enfant d'un autre élément. Je dois l'utiliser car IE ne prend pas en charge la méthode de l'élément .contains. J'espère que cela aidera les autres aussi.

Ci-dessous la fonction:

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;
}
2
RashFlash

essaye celui-là:

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";
}
1
user3675072