it-swarm.it

javascript document.getElementsByClassName compatibilità con IE

Qual è il metodo migliore per recuperare una matrice di elementi che hanno una certa classe?

Vorrei usare document.getElementsByClassName ma IE non lo supporta.

Quindi ho provato la soluzione di Jonathan Snook :

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');

... ma IE dice ancora:

L'oggetto non supporta questa proprietà o metodo

Qualche idea, metodi migliori, correzioni di bug?

Preferirei non utilizzare alcuna soluzione che coinvolga jQuery o altri "javascript ingombranti".

Aggiornare:

L'ho fatto funzionare!

Come @ joe menzionato la funzione non è un metodo di document.

Quindi il codice funzionante sarebbe simile al seguente:

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');


... Inoltre se hai bisogno solo del supporto IE8 + , questo funzionerà:

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

Usalo come al solito:

var tabs = document.getElementsByClassName('tab');
75
Web_Designer

Non è un metodo di documento:

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
55
Joe

puoi creare la funzione per i browser più vecchi

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;
    }
}
17
gdarcan
function getElementsByClassName(className) {
if (document.getElementsByClassName) { 
  return document.getElementsByClassName(className); }
else { return document.querySelectorAll('.' + className); } }

Abbastanza sicuro che questo è lo stesso della funzione di Leonid ma questo usa document.getElementsByClassName quando può.

13
Mike_OBrien

Non puoi davvero replicare getElementsByClassName, perché restituisce un nodeList, quindi il suo valore è attivo e si aggiorna con il documento.

Puoi restituire una matrice statica di elementi che condividono gli stessi nomi di classe, ma non "saprà" quando il documento cambia.

(Non ci vorranno troppe cose di questo genere per far sembrare una biblioteca snella ...)

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;
}

//Esempio

var A = getArrayByClassNames ('sideBar local')

10
kennebec

IE8:

document.getElementsByClassName = function (className) {
    return document.querySelectorAll('.' + className)
}
9
Leonid
function _getClass(whatEverClasNameYouWant){
var a=document.getElementsByTagName('*');
   for(b in a){
      if((' '+a[b].className+' ').indexOf(' '+whatEverClasNameYouWant+' ')>-1){
      return a[b];
      }
   }
}
0
Mohd Afique

Voglio solo migliorare querySelectorAll fallback per IE8.

Come altri hanno risposto, il modo più semplice è aggiungere la funzione a Element.prototype con

this.querySelectorAll('.' + className);

Ma ci sono alcuni problemi:

  • Non funziona con stringhe non tagliate (all'inizio).
  • Non funziona con più classi.
  • Non funziona con personaggi di classe "strani" (/, $, *, eccetera.)
  • Non funziona con le classi che iniziano con una cifra (identificatori non validi)

Ciò significa che dovrebbe esserci qualche "correzione", ad esempio:

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

Codice:

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
);
0
Oriol