Wie erhalte ich ein untergeordnetes Element anhand des Klassennamens?


131

Ich versuche, die untergeordnete Spanne mit einer Klasse = 4 zu ermitteln. Hier ein Beispielelement:

<div id="test">
 <span class="one"></span>
 <span class="two"></span>
 <span class="three"></span>
 <span class="four"></span>
</div>

Die Tools, die ich zur Verfügung habe, sind JS und YUI2. Ich kann so etwas machen:

doc = document.getElementById('test');
notes = doc.getElementsByClassName('four');

//or

doc = YAHOO.util.Dom.get('#test');
notes = doc.getElementsByClassName('four');

Diese funktionieren im IE nicht. Ich erhalte die Fehlermeldung, dass das Objekt (doc) diese Methode oder Eigenschaft (getElementsByClassName) nicht unterstützt. Ich habe einige Beispiele für browserübergreifende Implementierungen von getElementsByClassName ausprobiert, konnte sie jedoch nicht zum Laufen bringen und habe trotzdem diesen Fehler erhalten.

Ich denke, was ich brauche, ist ein Cross-Browser getElementsByClassName oder ich muss doc.getElementsByTagName ('span') verwenden und durchlaufen, bis ich Klasse 4 finde. Ich bin mir jedoch nicht sicher, wie ich das machen soll.



1
Komischerweise wird der leistungsstärkere querySelectorAllvon IE 8+ unterstützt, während er getElementsByClassNamenur von IE 9+ unterstützt wird. Wenn Sie IE 7 löschen können, können Sie es sicher verwenden querySelectorAll('.4'). Übrigens 4ist ein ungültiger Klassenname.
Prinzhorn

@paritybit Diese Frage funktioniert nicht, da sie immer noch getElementsByClassName verwendet und ältere Versionen des IE dies anscheinend nicht unterstützen. edit: Es tut mir leid, dass der Tag-Name verwendet wird. Dies kann funktionieren.
spyderman4g63

@Prinzhorn Ich habe aus irgendeinem Grund nicht das YUI2-Auswahlprogramm in diesem Produkt.
spyderman4g63

@ spyderman4g63 Ich habe über nichts YUI2-spezifisches gesprochen. document.querySelectorAllist DOM und hat nichts mit YUI zu tun
Prinzhorn

Antworten:


85

Verwenden Sie doc.childNodesdiese Option, um die einzelnen Elemente zu durchlaufen span, und filtern Sie dann diejenige, deren classNameGleichheit 4:

var doc = document.getElementById("test");
var notes = null;
for (var i = 0; i < doc.childNodes.length; i++) {
    if (doc.childNodes[i].className == "4") {
      notes = doc.childNodes[i];
      break;
    }        
}

.


1
Das Problem ist, dass getElementsByClassName in IE8 nicht funktioniert.
spyderman4g63

7
Dieser Code funktioniert nicht, wenn das Element mehr als eine Klasse hat. Beispiel: Wenn Sie nach Elementen mit der Klasse "eins" suchen und Ihre Elemente die Klasse "eins zwei drei" haben, werden sie von dieser Funktion nicht gefunden.
Fran Verona

3
@FranVerona Würde ein einfaches "indexOf ('className')> -1" nicht aus Neugier das Problem mit mehreren Klassen lösen?
James Poulose

2
@ JamesPoulose, würde es nicht . Ziehen Sie in Betracht, ein Element auf zwei Klassen festzulegen: klein und größer. thatElement.className würde einen String zurückgeben, der gleich "klein größer" ist. Wenn Sie nach einer Klasse mit dem Namen big suchen, sagt myElement.className.indexOf ("big") etwas, das nicht der negativen 1 entspricht, obwohl es eigentlich kein Teil der Klasse ist. Wenn Sie 100% Kontrolle über Ihre Klassennamen haben, würde eine solche Korrektur funktionieren, dies ist jedoch nicht garantiert, insbesondere wenn Sie Code schreiben, der mit Code interagiert, über den Sie keine vollständige Kontrolle haben.
Deadboy

Sie sollten eine Regex-Übereinstimmung für Folgendes verwenden className: if(doc.childNode[i].className.match("\s*" + search_class + "\s*")Dabei ist die Variable search_classder Klassenname, nach dem Sie suchen.
WebWanderer

130

Verwenden Sie querySelector und querySelectorAll

var testContainer = document.querySelector('#test');
var fourChildNode = testContainer.querySelector('.four');

IE9 und höher

;)


Vielen Dank für Ihre intelligente Lösung!
Tai JinYuan

1
Dies prüft auf alle Nachkommen, nicht nur auf Kinder.
SUM1

47

Die akzeptierte Antwort überprüft nur unmittelbare Kinder. Oft suchen wir nach Nachkommen mit diesem Klassennamen.

Manchmal möchten wir auch ein Kind, das einen Klassennamen enthält .

Beispiel: <div class="img square"></div>Sollte mit einer Suche nach Klassenname "img" übereinstimmen, obwohl der genaue Klassenname nicht "img" ist.

Hier ist eine Lösung für beide Probleme:

Suchen Sie die erste Instanz eines untergeordneten Elements mit der Klasse className

   function findFirstChildByClass(element, className) {
        var foundElement = null, found;
        function recurse(element, className, found) {
            for (var i = 0; i < element.childNodes.length && !found; i++) {
                var el = element.childNodes[i];
                var classes = el.className != undefined? el.className.split(" ") : [];
                for (var j = 0, jl = classes.length; j < jl; j++) {
                    if (classes[j] == className) {
                        found = true;
                        foundElement = element.childNodes[i];
                        break;
                    }
                }
                if(found)
                    break;
                recurse(element.childNodes[i], className, found);
            }
        }
        recurse(element, className, false);
        return foundElement;
    }

7
Nee. Ich möchte nicht alle Nachkommen, nur das Kind wie die gestellte Frage.
Paul Draper

14
Welpe. Ihr Kommentar war notwendig. Ich bin froh, dass ich 13 anderen Menschen geholfen habe, die (wie ich) oft nach ähnlichen Antworten suchen, um ihr ähnliches, aber vielleicht komplexeres oder allgemeineres Problem zu lösen.
Augie Gardner

5
tnx, ich denke, diese Antwort passt zu mehr Anwendungsfällen
Boban Stojanovski

Ich habe beide Anwendungsfälle gehabt, Nachkommen etwas häufiger, aber ich bin wegen des Anwendungsfalls für Kinder hierher gekommen.
SUM1

14

Verwenden Sie element.querySelector (). Nehmen wir an: 'myElement' ist das übergeordnete Element, das Sie bereits haben. 'sonClassName' ist die Klasse des Kindes, das Sie suchen.

let child = myElement.querySelector('.sonClassName');

Weitere Informationen finden Sie unter: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector


Aus irgendeinem Grund musste ich let child = myElement.querySelector('sonClassName');in meinem Fall
malat verwenden

Sie müssen jedoch den Punkt neben dem Klassennamen querySelector ('. SonClassName') einfügen, andernfalls wird er behandelt, da sonClassName ein Tag-Name und kein Klassenname ist
Hamza Dahmoun,

10

Du könntest es versuchen:

notes = doc.querySelectorAll('.4');

oder

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}

1
Ich habe mich gefragt, ob Browser diese Funktionalität endlich haben, ohne etwas wie jQuery zu benötigen. Ich bin froh, das zu sehen. Wenn jemand neugierig ist, sieht es so aus, als ob es in den meisten modernen Browsern unterstützt wird: developer.mozilla.org/en-US/docs/Web/API/Document/…
Liron Yahdav

8

Mir scheint, Sie wollen die vierte Spanne. Wenn ja, können Sie dies einfach tun:

document.getElementById("test").childNodes[3]

oder

document.getElementById("test").getElementsByTagName("span")[3]

Letzteres stellt sicher, dass es keine versteckten Knoten gibt, die es vermasseln könnten.


1
Danke, aber es gibt eine variable Anzahl von untergeordneten Elementen.
spyderman4g63

1
Für mich schien es die Frage zu sein, immer das Kind der vierten Spanne zu bekommen, was zu meiner Antwort führte. Ich stimme natürlich zu, dass eine Funktion zum Abrufen eines beliebigen Elementtyps an einem beliebigen Index in einem anderen Element besser wäre, aber ich habe die Frage nicht so interpretiert ... Wenn ich die Frage noch einmal lese, sehe ich, dass ich sie völlig missverstanden habe: )
Christian Jørgensen

TagNamedas ist es! So einfach.
Jacksonkr

Ich benutze diese Technik häufig, um das erste Element zu erhalten, z. B. document.getElementById ("test"). ChildNodes [0]
Louise Eggleton

@ LouisEggleton gibt es .firstChildund .firstChildElementobwohl
YakovL

4

Beachten Sie jedoch, dass alte Browser dies nicht unterstützen getElementsByClassName.

Dann können Sie tun

function getElementsByClassName(c,el){
    if(typeof el=='string'){el=document.getElementById(el);}
    if(!el){el=document;}
    if(el.getElementsByClassName){return el.getElementsByClassName(c);}
    var arr=[],
        allEls=el.getElementsByTagName('*');
    for(var i=0;i<allEls.length;i++){
        if(allEls[i].className.split(' ').indexOf(c)>-1){arr.push(allEls[i])}
    }
    return arr;
}
getElementsByClassName('4','test')[0];

Es scheint zu funktionieren, aber beachten Sie, dass eine HTML-Klasse

  • Muss mit einem Buchstaben beginnen: AZ oder az
  • Kann von Buchstaben (A-Za-z), Ziffern (0-9), Bindestrichen ("-") und Unterstrichen ("_") gefolgt werden.

3

Verwenden Sie den Namen der ID mit dem getElementById, kein #Zeichen davor. Dann können Sie die spanuntergeordneten Knoten verwenden getElementsByTagNameund sie durchlaufen, um den Knoten mit der richtigen Klasse zu finden:

var doc = document.getElementById('test');

var c = doc.getElementsByTagName('span');

var e = null;
for (var i = 0; i < c.length; i++) {
    if (c[i].className == '4') {
        e = c[i];
        break;
    }
}

if (e != null) {
    alert(e.innerHTML);
}

Demo: http://jsfiddle.net/Guffa/xB62U/


Entschuldigung, das # war ein Tippfehler. Ich kann den Container div auswählen, aber die untergeordneten Elemente nicht nach Tag-Namen auswählen, da diese Funktion in ie8 nicht funktioniert.
spyderman4g63

@ spyderman4g63: Die getElementsByTagNameMethode funktioniert in IE 8. Sie wird bereits in IE 5.5 unterstützt. developer.mozilla.org/en-US/docs/DOM/…
Guffa

3

Meiner Meinung nach sollten Sie jedes Mal, wenn Sie können, Array und seine Methoden verwenden. Sie sind viel, viel schneller als das gesamte DOM / Wrapper zu durchlaufen oder Dinge in ein leeres Array zu schieben. Die meisten der hier vorgestellten Lösungen können Sie wie hier beschrieben Naive nennen (großartiger Artikel übrigens):

https://medium.com/@chuckdries/traversing-the-dom-with-filter-map-and-arrow-functions-1417d326d2bc

Meine Lösung : (Live-Vorschau auf Codepen: https://codepen.io/Nikolaus91/pen/wEGEYe )

const wrapper = document.getElementById('test') // take a wrapper by ID -> fastest
const itemsArray = Array.from(wrapper.children) // make Array from his children

const pickOne = itemsArray.map(item => { // loop over his children using .map() --> see MDN for more
   if(item.classList.contains('four')) // we place a test where we determine our choice
     item.classList.add('the-chosen-one') // your code here
})

1

Die Art und Weise, wie ich dies mit jquery mache, ist ungefähr so.

var targetchildchild = $ ("# test"). children (). find ("span.four");


14
Frage ist über Javascript nicht jQuery
Jya

1

Hier ist eine relativ einfache rekursive Lösung. Ich denke, eine Breitensuche ist hier angebracht. Dies gibt das erste Element zurück, das der gefundenen Klasse entspricht.

function getDescendantWithClass(element, clName) {
    var children = element.childNodes;
    for (var i = 0; i < children.length; i++) {
        if (children[i].className &&
            children[i].className.split(' ').indexOf(clName) >= 0) {
            return children[i];
         }
     }
     for (var i = 0; i < children.length; i++) {
         var match = getDescendantWithClass(children[i], clName);
         if (match !== null) {
             return match;
         }
     }
     return null;
}

1

Sie können die übergeordnete Klasse abrufen, indem Sie die folgende Zeile hinzufügen. Wenn Sie einen Ausweis hätten, wäre es einfacher mit getElementById. Dennoch,

var parentNode = document.getElementsByClassName("progress__container")[0];

Anschließend können Sie querySelectorAllauf dem übergeordneten <div>Element alle übereinstimmenden divs mit der Klasse abrufen.progress__marker

var progressNodes = progressContainer.querySelectorAll('.progress__marker');

querySelectorAllwird jeden divmit der Klasse von holenprogress__marker


1

Moderne Lösung

const context = document.getElementById('context');
const selected = context.querySelectorAll(':scope > div');

Dokumentation


0

Juni 2018 Update auf ES6

    const doc = document.getElementById('test');
    let notes = null;
    for (const value of doc) {
        if (value.className === '4') {
            notes = value;
            break;
        }    
    }

-2

Hmm. Das Beispiel funktioniert in IE8, aber möglicherweise nicht, wenn Sie es auf ein Objekt anwenden. In meinem Fall wird doc als yui dom-Objekt festgelegt und dann doc.getElementsByClassName verwendet. Dann scheitert es. edit: oder verstehe ich vielleicht nicht wie dieses objekt funktioniert und es ist nur ein normales dom objekt?
spyderman4g63

@ spyderman4g63 Die YUI-Version von getElementsByClassNameist eine Methode von YAHOO.util.Dom. In Ihrem Fall würde der Anruf ungefähr so ​​aussehen YAHOO.util.Dom.getElementsByClassName('four', 'span', 'test'). Sie sollten wahrscheinlich die Dokumente lesen, um ein detaillierteres Verständnis der Funktionsweise dieses Aufrufs zu erhalten. Die Kurzversion ist, dass jetzt nach spanElementen mit der Klasse fourunter dem DOM-Element mit testals gesucht wird id.
Hank Gay

@ spyderman4g63 Ja, das Ergebnis des getAufrufs ist nur ein DOM-Element. YUI verfolgt nicht die Art von "Alles in ein Framework-spezifisches Objekt einwickeln" -Ansatz wie jQuery, und es werden auch keine nativen Objekte wie Prototype gepatcht (habe? Ich habe mich nicht mit Protoype angelegt) in für immer). In dieser Hinsicht ähnelt YUI eher Dojo.
Hank Gay

-3

Hier ist, wie ich es mit den YUI-Selektoren gemacht habe. Dank des Vorschlags von Hank Gay.

notes = YAHOO.util.Dom.getElementsByClassName('four','span','test');

Dabei sind vier = Klassenname, span = Elementtyp / Tag-Name und test = übergeordnete ID.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.