Kompatibilität von Javascript document.getElementsByClassName mit IE

76

Was ist die beste Methode, um ein Array von Elementen mit einer bestimmten Klasse abzurufen?

Ich würde document.getElementsByClassName verwenden, aber der IE unterstützt es nicht.

Also habe ich Jonathan Snooks Lösung ausprobiert :

function getElementsByClassName(node, classname) {
    var a = [];
    var re = new RegExp('(^| )'+classname+'( |$)');
    var els = node.getElementsByTagName("*");
    for(var i=0,j=els.length; i<j; i++)
        if(re.test(els[i].className))a.push(els[i]);
    return a;
}
var tabs = document.getElementsByClassName(document.body,'tab');

... aber IE sagt immer noch:

Object unterstützt diese Eigenschaft oder Methode nicht

Irgendwelche Ideen, bessere Methoden, Fehlerbehebungen?

Ich würde es vorziehen, keine Lösungen mit jQuery oder anderem "sperrigem Javascript" zu verwenden.

Aktualisieren:

Ich habe es zum Laufen gebracht!

Wie @joe erwähnte, ist die Funktion keine Methode von document.

Der Arbeitscode würde also so aussehen:

function getElementsByClassName(node, classname) {
    var a = [];
    var re = new RegExp('(^| )'+classname+'( |$)');
    var els = node.getElementsByTagName("*");
    for(var i=0,j=els.length; i<j; i++)
        if(re.test(els[i].className))a.push(els[i]);
    return a;
}
var tabs = getElementsByClassName(document.body,'tab');


... Auch wenn Sie nur IE8 + -Unterstützung benötigen, funktioniert dies:

if(!document.getElementsByClassName) {
    document.getElementsByClassName = function(className) {
        return this.querySelectorAll("." + className);
    };
    Element.prototype.getElementsByClassName = document.getElementsByClassName;
}

Verwenden Sie es wie gewohnt:

var tabs = document.getElementsByClassName('tab');
Webdesigner
quelle
2
Sind Sie sicher, dass Ihr Update richtig ist? Sollte es nicht var tabs = getElementsByClassName sein (document.body, 'tab'); **
Anthony
Sind Ihre letzten Beispiele richtig? Sie übergeben '.tab', aber sollte es nicht ohne den Punkt sein, da Ihre innere Methode den Punkt hinzufügt und wenn es IE9 + ist, hat es auch keinen Punkt? Sollte es nicht var tabs = document.getElementsByClassName ('tab') sein? Und warum haben Sie ein "oder", wenn die letzten beiden Beispiele gleich sind? Mir muss etwas fehlen.
BoBoCoding
@BoBoCoding behoben.
Web_Designer
Siehe auch getElementsByClassNamePolyfill- Kern in Polyfill für getElementsByClassName für bestimmte Verwendungszwecke .
Vadzim

Antworten:

56

Es ist keine Methode des Dokuments:

function getElementsByClassName(node, classname) {
    var a = [];
    var re = new RegExp('(^| )'+classname+'( |$)');
    var els = node.getElementsByTagName("*");
    for(var i=0,j=els.length; i<j; i++)
        if(re.test(els[i].className))a.push(els[i]);
    return a;
}

tabs = getElementsByClassName(document.body,'tab');  // no document
Joe
quelle
Testen Sie auf jsFiddle.net oder Ihrem eigenen Server / Computer?
Joe
@inquisitive_web_developer - Welchen Fehler bekommen Sie jetzt? Auf welcher Linie bricht es?
nnnnnn
17

Sie können die Funktion für ältere Browser erstellen

if (typeof document.getElementsByClassName!='function') {
    document.getElementsByClassName = function() {
        var elms = document.getElementsByTagName('*');
        var ei = new Array();
        for (i=0;i<elms.length;i++) {
            if (elms[i].getAttribute('class')) {
                ecl = elms[i].getAttribute('class').split(' ');
                for (j=0;j<ecl.length;j++) {
                    if (ecl[j].toLowerCase() == arguments[0].toLowerCase()) {
                        ei.push(elms[i]);
                    }
                }
            } else if (elms[i].className) {
                ecl = elms[i].className.split(' ');
                for (j=0;j<ecl.length;j++) {
                    if (ecl[j].toLowerCase() == arguments[0].toLowerCase()) {
                        ei.push(elms[i]);
                    }
                }
            }
        }
        return ei;
    }
}
gdarcan
quelle
14
function getElementsByClassName(className) {
if (document.getElementsByClassName) { 
  return document.getElementsByClassName(className); }
else { return document.querySelectorAll('.' + className); } }

Ich bin mir ziemlich sicher, dass dies die gleiche Funktion wie Leonid ist, aber dies wird verwendet, document.getElementsByClassNamewenn es möglich ist.

Mike_OBrien
quelle
10

Sie können getElementsByClassName nicht wirklich replizieren, da es eine nodeList zurückgibt und sein Wert daher aktiv ist und mit dem Dokument aktualisiert wird.

Sie können ein statisches Array von Elementen zurückgeben, die dieselben Klassennamen haben, aber nicht wissen, wann sich das Dokument ändert.

(Es werden nicht zu viele dieser Dinge nötig sein, um eine Bibliothek schlank aussehen zu lassen ...)

function getArrayByClassNames(classes, pa){
    if(!pa) pa= document;
    var C= [], G;
    if(pa.getElementsByClassName){
        G= pa.getElementsByClassName(classes);
        for(var i= 0, L= G.length; i<L; i++){
            C[i]= G[i];
        }
    }
    else{
        classes= classes.split(/\s+/);
        var who, cL= classes.length,
        cn, G= pa.getElementsByTagName('*'), L= G.length;
        for(var i= 0; i<cL; i++){
            classes[i]= RegExp('\\b'+classes[i]+'\\b');
        }
        classnameLoop:
        while(L){
            who= G[--L];
            cn= who.className;
            if(cn){
                for(var i= 0; i<cL; i++){
                    if(classes[i].test(cn)== false) {
                        continue classnameLoop;
                    }
                }
                C.push(who);
            }
        }
    }
    return C;
}

//Beispiel

var A = getArrayByClassNames ('sideBar local')

kennebec
quelle
3
+1 für die Feststellung, dass getElementsByClassNamedie Kompatibilitäts-Hacks (einschließlich querySelectorAll) im Gegensatz zum Real statische Snapshots und keine Live-Sammlungen liefern.
Søren Løvborg
9

IE8:

document.getElementsByClassName = function (className) {
    return document.querySelectorAll('.' + className)
}
Leonid
quelle
1
Funktioniert nicht auf meinem IE9: "Objekt unterstützt keine Eigenschaft oder Methode 'querySelectorAll'"
Phil
0
function _getClass(whatEverClasNameYouWant){
var a=document.getElementsByTagName('*');
   for(b in a){
      if((' '+a[b].className+' ').indexOf(' '+whatEverClasNameYouWant+' ')>-1){
      return a[b];
      }
   }
}
Mohd Afique
quelle
0

Ich möchte nur den querySelectorAllFallback für IE8 verbessern .

Wie andere geantwortet haben, besteht der einfache Weg darin, die Funktion Element.prototypemit hinzuzufügen

this.querySelectorAll('.' + className);

Es gibt jedoch einige Probleme:

  • Es funktioniert nicht mit unbeschnittenen Zeichenfolgen (am Anfang).
  • Es funktioniert nicht mit mehreren Klassen.
  • Es funktioniert nicht mit „fremden“ Klassenzeichen funktioniert ( /, $, *, etc.)
  • Es funktioniert nicht mit Klassen, die mit einer Ziffer beginnen (ungültige Bezeichner).

Das heißt, es sollte einige "Korrekturen" geben, zum Beispiel:

"abcd"     ->  ".abcd"
"a   b cd" ->  ".a.b.cd"
"   a b  " ->  ".a.b  "
"a/b$c d"  ->  ".a\/b\$c.d"
"1234"     ->  ".\000031234"

Code:

this.querySelectorAll(className
    .replace(/(?=[^ \w])/g, '\\')   // Escape non-word characters
    .replace(/\b\d/g, '\\00003$&')  // Escape digits at the beginning
    .replace(/(^| +)(?!$| )/g, '.') // Add "." before classes, removing spaces
);
Oriol
quelle
1
Die Funktion kann auch hinzugefügt HTMLDocument.prototypewerden, um sie mit zu verwenden document.
Oriol