it-swarm.com.de

Beste Möglichkeit, untergeordnete Knoten zu erhalten

Ich habe mich gefragt, ob JavaScript eine Vielzahl von Methoden bietet, um das erste untergeordnete Element aus einem beliebigen Element abzurufen. Aber welches ist das Beste? Mit "am besten" meine ich: am browserübergreifendsten, am schnellsten, am umfassendsten und am vorhersehbarsten in Bezug auf das Verhalten. Eine Liste von Methoden/Eigenschaften, die ich als Aliase verwende:

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

Dies funktioniert in beiden Fällen:

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

Dies ist bei Formularen der Fall oder bei einer <div> -Iteration. Wenn ich auf Textelemente stoßen könnte:

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

Soweit ich das beurteilen kann, verwendet firstChild die NodeList aus childNodes, und firstElementChild verwendet children. Ich stütze diese Annahme auf die MDN-Referenz:

childNode ist eine Referenz auf das erste untergeordnete Element des Elementknotens oder null, falls es keines gibt.

Ich vermute, dass in Bezug auf die Geschwindigkeit der Unterschied, wenn überhaupt, so gut wie nichts sein wird, da firstElementChild tatsächlich eine Referenz auf children[0] ist und das children -Objekt bereits vorhanden ist sowieso in Erinnerung.

Was mich jedoch auslöst, ist das Objekt childNodes. Ich habe es verwendet, um ein Formular in einem Tabellenelement zu betrachten. Während children alle Formularelemente auflistet, scheint childNodes auch Leerzeichen aus dem HTML-Code zu enthalten:

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

Beide log <TextNode textContent="\n ">

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

Alle log <input type="text">. Woher? Ich verstehe, dass ein Objekt mir erlauben würde, mit dem "rohen" HTML-Code zu arbeiten, während das andere am DOM festhält, aber das childNodes -Element scheint auf beiden Ebenen zu funktionieren.

Um auf meine ursprüngliche Frage zurückzukommen, würde ich raten: Wenn ich das umfassendste Objekt haben möchte, ist childNodes der richtige Weg, aber aufgrund seiner Vollständigkeit ist es möglicherweise nicht der vorhersehbarste, was die Rückgabe angeht das Element, das ich zu einem bestimmten Zeitpunkt will/erwarte. Die browserübergreifende Unterstützung könnte sich in diesem Fall ebenfalls als Herausforderung erweisen, obwohl ich mich irren könnte.

Könnte jemand die Unterscheidung zwischen den Gegenständen klarstellen? Wenn es einen Geschwindigkeitsunterschied gibt, der jedoch vernachlässigbar ist, würde ich gerne auch wissen. Wenn ich das alles falsch sehe, kannst du mich gerne aufklären.


PS: Bitte, bitte, ich mag JavaScript, also ja, ich möchte mit so etwas umgehen. Antworten wie "jQuery erledigt dies für Sie" sind nicht das, wonach ich suche, daher kein jquery -Tag.

216

Klingt so, als würdest du es überdenken. Sie haben den Unterschied zwischen childNodes und children festgestellt, nämlich, dass childNodes alle Knoten enthält, einschließlich Textknoten, die ausschließlich aus Leerzeichen bestehen, während children eine Sammlung von nur ist Die untergeordneten Knoten, die Elemente sind. Das ist wirklich alles was dazu gehört.

An beiden Sammlungen ist nichts Unvorhersehbares zu erkennen, obwohl einige Punkte zu beachten sind:

  • IE <= 8 enthält keine Nur-Leerzeichen-Textknoten in childNodes, während andere Browser dies tun
  • IE <= 8 enthält Kommentarknoten in children, während andere Browser nur Elemente enthalten

children, firstElementChild und Freunde sind nur Annehmlichkeiten, die eine gefilterte Ansicht des DOM darstellen, die auf nur Elemente beschränkt ist.

204
Tim Down

firstElementChild ist möglicherweise nicht in IE <9 verfügbar (nur firstChild)

auf IE <9 firstChild ist das firstElementChild, da MS DOM (IE <9) keine leeren Textknoten speichert. Wenn Sie dies jedoch in anderen Browsern tun, werden leere Textknoten zurückgegeben ...

meine Lösung

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

dies wird das erste Kind auch auf IE <9 geben

23
neu-rah

Der browserübergreifende Weg besteht darin, childNodes zu verwenden, um NodeList zu erhalten, und dann ein Array aller Knoten mit nodeTypeELEMENT_NODE zu erstellen.

_/**
 * 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/

Dies ist besonders einfach, wenn Sie eine Hilfsprogrammbibliothek wie lodash verwenden:

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

Zukunft:

Sie können querySelectorAll in Kombination mit :scope Pseudoklasse verwenden (entspricht dem Element, das der Referenzpunkt des Selektors ist):

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

Zum Zeitpunkt des Schreibens wird dieses _:scope_ in Chrome, Firefox und Safari unterstützt .

16
Gajus

Nur um die anderen Antworten zu ergänzen, gibt es hier immer noch bemerkenswerte Unterschiede, insbesondere wenn es um <svg> -Elemente geht.

Ich habe sowohl .childNodes als auch .children verwendet und es vorgezogen, mit dem HTMLCollection zu arbeiten, der vom Getter .children geliefert wird.

Heute bin ich jedoch auf Probleme mit IE/Edge gestoßen, wenn .children auf einem <svg> verwendet wurde. Während .children in IE für grundlegende HTML-Elemente unterstützt wird, wird nicht für Dokument-/Dokumentfragmente unterstützt, oder SVG-Elemente .

Für mich war es einfach möglich, die benötigten Elemente über .childNodes[n] zu erfassen, da ich keine unnötigen Textknoten habe, um die ich mich sorgen müsste. Möglicherweise können Sie das Gleiche tun, aber vergessen Sie nicht, dass Sie, wie oben erwähnt, auf unerwartete Elemente stoßen können.

Hoffe, dies ist hilfreich für jemanden, der sich am Kopf kratzt, um herauszufinden, warum .children an einer anderen Stelle in seinem js auf modernen IE funktioniert und bei Dokumenten- oder SVG-Elementen fehlschlägt.

3
slothluvchunk

Hey Leute, lasst euch nicht vom Leerraum täuschen. Testen Sie dies einfach in einem Konsolenbrowser. benutze natives Javascript. Hier ist ein Beispiel mit zwei 'ul'-Mengen mit derselben Klasse. Sie müssen Ihre 'ul'-Liste nicht in einer Zeile haben, um Leerzeichen zu vermeiden. Verwenden Sie einfach Ihre Array-Anzahl, um über Leerzeichen zu springen.

Wie man sich mit querySelector() und dann childNodes[] im Leerraum zurechtfindet: 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