javascript document.getElementsByClassName compati

2018-12-31 12:04发布

问题:

What is the best method to retrieve an array of elements that have a certain class?

I would use document.getElementsByClassName but IE does not support it.

So I tried Jonathan Snook\'s solution:

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

...but IE still says:

Object doesn\'t support this property or method

Any ideas, better methods, bug fixes?

I would prefer not to use any solutions involving jQuery or other \"bulky javascript\".

Update:

I got it to work!

As @joe mentioned the function is not a method of document.

So the working code would look like this:

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


...Also if you only need IE8+ support then this will work:

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

Use it just like normal:

var tabs = document.getElementsByClassName(\'tab\');

回答1:

It\'s not a method of document:

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


回答2:

you may create the function for older browsers

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


回答3:

function getElementsByClassName(className) {
if (document.getElementsByClassName) { 
  return document.getElementsByClassName(className); }
else { return document.querySelectorAll(\'.\' + className); } }

Pretty sure this is the same as Leonid\'s function but this uses document.getElementsByClassName when it can.



回答4:

You can\'t really replicate getElementsByClassName, because it returns a nodeList, and so its value is live, and updates with the document.

You can return a static Array of elements who share the same classnames- but it won\'t \'know\'when the document changes.

(It won\'t take too many of these kind of things to make a library look svelte...)

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

//Example

var A= getArrayByClassNames(\'sideBar local\')



回答5:

IE8:

document.getElementsByClassName = function (className) {
    return document.querySelectorAll(\'.\' + className)
}


回答6:

function _getClass(whatEverClasNameYouWant){
var a=document.getElementsByTagName(\'*\');
   for(b in a){
      if((\' \'+a[b].className+\' \').indexOf(\' \'+whatEverClasNameYouWant+\' \')>-1){
      return a[b];
      }
   }
}


回答7:

I just want to improve querySelectorAll fallback for IE8.

Like others answered, the simple way is adding the function to Element.prototype with

this.querySelectorAll(\'.\' + className);

But there are some problems:

  • It doesn\'t work with untrimmed strings (at the beginning).
  • It doesn\'t work with multiple classes.
  • It doesn\'t work with \"strange\" class characters (/, $, *, etc.)
  • It doesn\'t work with classes which begin with a digit (invalid identifiers)

That means there should be some \"fixing\", for example:

\"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
);