getElementsByClassName () mit zwei Klassen

73

Ist es möglich , alle Elemente mit Klasse zu erhalten a oder b mit getElementsByClassName()nur einmal? Ich würde Vanille JavaScript bevorzugen.

Unbekannter Entwickler
quelle

Antworten:

123

Sie können dies nicht mit der getElementsByClassName()Methode tun , sondern verwenden Sie die querySelectorAll()Methode mit durch Kommas getrennten Klassenselektoren.

document.querySelectorAll('.a,.b')
Pranav C Balan
quelle
2
Dies ist die richtige Antwort. Beachten Sie jedoch, dass IE8 nur für CSS2-Selektoren unterstützt wird und IE <= 7 nicht unterstützt wird. In diesem Fall müssen Sie zwei Auswahlen nach Klassen vornehmen.
Zoubida13
1
Ich sehe Ihre Bearbeitung, aber getElementsByClassName funktioniert auch in IE <= 7 nicht. Ich poste eine alternative Antwort, um dies zu vervollständigen, aber Ihre sollte von OP als beste Antwort gewählt werden.
Zoubida13
1
@ zoubida13: Wie sind .a,.bnicht nur zwei CSS2-Selektoren?
BoltClock
3
@ zoubida13: Ich glaube nicht, dass es Leute gibt, die noch verwenden IE <= 7:);)
Pranav C Balan
5
Selbst Microsoft unterstützt IE7 nicht mehr. Warum Firmen oder Entwickler das immer noch tun, kann ich nicht verstehen!
Sertsedat
20

Sie können mehr als einen Klassennamen übergeben, getElementsByClassName()indem Sie sie durch Leerzeichen trennen:

var elems = document.getElementsByClassName("class1 class2 class3");

Dies unterscheidet sich vom .querySelectorAll(".class1,.class2,.class3")Ansatz darin, dass eine Konjunktion angewendet wird , keine Disjunktion - "und" anstelle von "oder". So

var elems = document.getElementsByClassName("class1 class2 class3");

ist wie

var elems = document.querySelectorAll(".class1.class2.class3");

Manchmal willst du eins, manchmal willst du das andere. Es ist definitiv wahr, dass .querySelectorAll()Sie viel mehr Flexibilität geben.

Spitze
quelle
5
Das ist nicht richtig. Es wird nach Elementen suchen, die alle drei Klassen haben
Unbekannter Entwickler
7
Das ist ein "UND", kein "ODER"
Epascarello
1
@epascarello ja ich sehe das; Es ist nur eine Antwort.
Pointy
2
Diese Antwort funktioniert nicht. Es werden nur Elemente mit allen angegebenen Klassen zurückgegeben.
Andy Mercer
6
Es ist eine Antwort, bei der die falsche Frage beantwortet wird. Die bereitgestellten Informationen sind für die gestellte Frage nicht genau relevant. Und mehr als wahrscheinlich weiß das OP bereits. Daher ist dies meistens Lärm.
Spencer Wieczorek
8

Nein, das können Sie nicht mit nur einem document.getElementsByClassName()Anruf erreichen. Diese Funktion gibt Elemente zurück, bei denen alle im ersten Argument angegebenen Klassen als durch Leerzeichen getrennte Zeichenfolge vorliegen.

Es gibt zwei mögliche Lösungen. Zunächst wird document.querySelectorAll()stattdessen CSS-Selektoren verwendet.

document.querySelectorAll(".a, .b")

Die zweite Lösung besteht darin, document.getElementsByClassName()zweimal aufzurufen , die Ergebnisse mit Arrays umzuwandeln Array.from()und sie mit zusammenzuführen Array.prototype.concat(). Um Duplikate zu vermeiden (z. B. wenn das Element sowohl a als auch eine bKlasse enthält), müssen Sie aus diesem Array einen neuen Satz erstellen und ihn dann mithilfe von wieder in das Array zurücksetzen Array.from().

const classA = Array.from(document.getElementsByClassName("a"))
     ,classB = Array.from(document.getElementsByClassName("b"))
     ,result = Array.from(new Set(classA.concat(classB)))

Siehe Demo unten:

console.log("first solution", document.querySelectorAll(".a, .b"))

const classA = Array.from(document.getElementsByClassName("a"))
     ,classB = Array.from(document.getElementsByClassName("b"))
     ,result = Array.from(new Set(classA.concat(classB)))

console.log("second solution", result)
<div class="a"></div>
<div class="b"></div>
<div class="a b"></div>
<div class="c"></div>

Beachten Sie, dass die erste Lösung ein Array-ähnliches NodeListObjekt ergibt, während die zweite nur ein Array ergibt.

Michał Perłakowski
quelle
3
Es ist sinnlos, Set zu verwenden, da es in diesen Browsern nicht unterstützt wird, was querySelectorAll nicht unterstützt.
Somnium
3
@ Somnium Es ist nicht so sinnlos, wie es aussieht. Babel unterstützt Set, aber nicht document.querySelectorAll()(da es nicht Teil von ECMAScript, sondern von Web-APIs ist). Wenn Sie Ihren Code mit Babel kompilieren, funktioniert die zweite Lösung in allen Browsern. Und ehrlich gesagt habe ich die zweite Lösung eher zum Spaß als als echte Lösung geschrieben.
Michał Perłakowski
Array.from erzeugt ein Problem im Internet Explorer 11.
Kamlesh
6

Um ein bisschen mehr Unterstützung hinzuzufügen, hier ist eine Version, die mit älteren Versionen von IE kompatibel ist und reine Vanille-JS verwendet:

function getElementsByClassNameOr(root, classNameString) // classNameString like '.a, .b' don't forget the comma separator
 {
    var arr = [],
    rx = new RegExp('(^|[ \n\r\t\f])' + classNameString + '([ \n\r\t\f]|$)'),
    elements = root.getElementsByTagName("*");

    var elem;

    for (i=0 ; i < elements.length ; i++) {
        elem = elements[i];
        if (rx.test(elem.className)) {
            arr.push(elem);
        }

    }

    return arr; // will contain all the elements that have one of the classes in ClassNameString, root can be document or a div.
}
zoubida13
quelle
1
Dies wird sehr ineffizient sein. Beachten Sie, dass durch die Unterstützung älterer Browser auf much slowerBrowser abgezielt wird. Die Leistung ist in dieser Situation von entscheidender Bedeutung. Ich empfehle, mehrere Aufrufe zu verwenden Element.getElementsByClassNameund ein verkettetes Array der Ergebnisse zu verwenden.
Tim
1
@Tim Sie haben Recht mit der Leistung, obwohl die Tatsache, dass die Leistung in dieser Situation kritisch ist, ganz auf Ihre Interpretation zurückzuführen ist. Und Ihr Vorschlag ist weder gültig noch detailliert. getElementsByClassName wird in IE <9 nicht vollständig unterstützt.
zoubida13
1
@ zoubida13 Du hast vollkommen recht. Es scheint keinen anderen Weg als diese Antwort mit besserer Leistung zu geben.
Tim
1
@Blender Ich habe ein Komma durch ein Semikolon ersetzt, es war in der Tat ein Tippfehler ja.
Zoubida13
1
@ zoubida13: Ihr Code geht davon aus, dass die Klassennamen direkt nebeneinander liegen, sodass dies class="a b c"bei der Suche mit nicht funktioniert 'a c'.
Blender