web-dev-qa-db-fra.com

Meilleur moyen d'obtenir des nœuds enfants

Je me demandais, JavaScript offre une variété de méthodes pour obtenir le premier élément enfant à partir de n'importe quel élément, mais quelle est la meilleure? Par meilleur, je veux dire: la plupart des navigateurs compatibles, le plus rapide, le plus complet et le plus prévisible en matière de comportement. Une liste de méthodes/propriétés que j'utilise comme alias:

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]

Cela fonctionne pour les deux cas:

var child = elem.childNodes[0]; // or childNodes[1], see below

C’est le cas pour les formulaires, ou <div> itération. Si je pouvais rencontrer des éléments de texte:

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;

Autant que je sache, firstChild utilise la liste de noeuds de childNodes et firstElementChild utilise children. Je base cette hypothèse sur la référence MDN:

childNode est une référence au premier élément enfant du nœud de l’élément, ou null s’il n’en existe pas.

J'imagine qu'en termes de rapidité, la différence, s'il y en a une, sera presque nulle, puisque firstElementChild est en réalité une référence à children[0] et que l'objet children est déjà en mémoire quand même.

Ce qui me jette, c'est l'objet childNodes. Je l’ai utilisé pour examiner un formulaire, dans un élément de tableau. Alors que children répertorie tous les éléments de formulaire, childNodes semble également inclure des espaces à partir du code HTML:

console.log(elem.childNodes[0]);
console.log(elem.firstChild);

Tous les deux journal <TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);

Tous les journaux <input type="text">. Comment venir? Je comprendrais qu’un objet me permettrait de travailler avec le code HTML "brut", tandis que l’autre reste collé au DOM, mais l’élément childNodes semble fonctionner aux deux niveaux.

Pour revenir à ma question initiale, je suppose que si je veux l’objet le plus complet, childNodes est la voie à suivre, mais en raison de son exhaustivité, il n’est peut-être pas le plus prévisible en termes de retour l'élément que je veux/attends à un moment donné. La prise en charge inter-navigateurs peut également s'avérer être un défi dans ce cas, bien que je puisse me tromper.

Quelqu'un pourrait-il clarifier la distinction entre les objets à portée de main? S'il existe une différence de vitesse, même négligeable, j'aimerais le savoir également. Si je vois tout cela de travers, n’hésitez pas à me renseigner.


PS: S'il vous plaît, s'il vous plaît, j'aime JavaScript, donc oui, je veux m'occuper de ce genre de chose. Des réponses telles que "jQuery traite cela pour vous" ne sont pas ce que je recherche, donc pas de balise jquery .

216
Elias Van Ootegem

On dirait que tu y penses. Vous avez observé la différence entre childNodes et children, c'est-à-dire que childNodes contient tous les nœuds, y compris les nœuds de texte composés entièrement d'espaces, tandis que children est une collection de les nœuds enfants qui sont des éléments. C'est vraiment tout ce qu'il y a à faire.

Aucune de ces collections n’a rien d’imprévisible, bien qu’il y ait quelques problèmes à connaître:

  • IE <= 8 n’inclut pas les nœuds de texte contenant uniquement des espaces dans childNodes alors que les autres navigateurs l’incluent
  • IE <= 8 inclut des nœuds de commentaire dans children, tandis que les autres navigateurs ne comportent que des éléments.

children, firstElementChild et les amis ne sont que des commodités, présentant une vue filtrée du DOM limitée à des éléments uniquement.

204
Tim Down

firstElementChild n'est peut-être pas disponible dans IE <9 (uniquement firstChild)

sur IE <9, firstChild est le premierElementChild car MS DOM (IE <9) ne stocke pas de nœuds de texte vides. Mais si vous le faites sur d'autres navigateurs, ils renverront des nœuds de texte vides ...

ma solution

child=(elem.firstElementChild||elem.firstChild)

cela donnera le premier enfant même sur IE <9

23
neu-rah

La méthode à utiliser entre navigateurs consiste à utiliser childNodes pour obtenir NodeList, puis créez un tableau de tous les nœuds avec nodeTypeELEMENT_NODE .

_/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    var childNodes = element.childNodes,
        children = [],
        i = childNodes.length;

    while (i--) {
        if (childNodes[i].nodeType == 1) {
            children.unshift(childNodes[i]);
        }
    }

    return children;
}
_

http://jsfiddle.net/s4kxnahu/

Ceci est particulièrement facile si vous utilisez une bibliothèque d’utilitaires telle que lodash :

_/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    return _.where(element.childNodes, {nodeType: 1});
}
_

Futur:

Vous pouvez utiliser querySelectorAll en combinaison avec :scope pseudo-classe (correspond à l'élément qui est le point de référence du sélecteur):

_parentElement.querySelectorAll(':scope > *');
_

Au moment de la rédaction de cet article _:scope_ est pris en charge sous Chrome, Firefox et Safari.

16
Gajus

Pour ajouter aux autres réponses, il existe encore des différences notables ici, en particulier lorsque vous utilisez des éléments <svg>.

J'ai utilisé à la fois .childNodes et .children et j'ai préféré travailler avec le HTMLCollection fourni par le .children getter.

Aujourd'hui, cependant, j'ai rencontré des problèmes avec IE/Edge qui échouaient lors de l'utilisation de .children sur un <svg>. Bien que .children soit pris en charge dans IE sur des éléments HTML de base, il n'est pas pris en charge sur les documents/fragments de document, ou éléments SVG .

Pour moi, j'ai simplement pu récupérer les éléments nécessaires via .childNodes[n] parce que je n'ai pas à me soucier de nœuds de texte superflus. Vous pourrez peut-être faire la même chose, mais comme mentionné plus haut, n'oubliez pas que vous risquez de rencontrer des éléments inattendus.

J'espère que cela aidera ceux qui se grattent la tête à essayer de comprendre pourquoi .children fonctionne ailleurs dans leur js sur les IE modernes _ et échoue sur les éléments de document ou SVG.

3
slothluvchunk

Hé les gars, ne laissez pas l'espace blanc vous tromper. il suffit de tester cela dans un navigateur de console. utilisez javascript natif. Voici un exemple avec deux ensembles 'ul' avec la même classe. Vous n'avez pas besoin d'avoir votre liste "ul" sur une seule ligne pour éviter les espaces, utilisez simplement le nombre de tableaux pour sauter par-dessus les espaces.

Comment se déplacer dans les espaces vides avec querySelector() puis childNodes[] js fiddle link: https://jsfiddle.net/aparadise/56njekdo/

var y = document.querySelector('.list');
var myNode = y.childNodes[11].style.backgroundColor='red';

<ul class="list">
    <li>8</li>
    <li>9</li>
    <li>100</li>
</ul>

<ul class="list">
    <li>ABC</li>
    <li>DEF</li>
    <li>XYZ</li>
</ul>
2
andre paradise