совместимость javascript document.getElementsByClassName с IE

Как лучше всего получить массив элементов определенного класса?

Я бы использовал document.getElementsByClassName, но IE его не поддерживает.

Поэтому я попробовал решение Джонатана Снука:

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

... но IE по-прежнему говорит:

Объект не поддерживает это свойство или метод

Любые идеи, лучшие методы, исправления ошибок?

Я бы предпочел не использовать какие-либо решения, связанные с jQuery или другим «громоздким javascript».

Обновлять:

Я заставил его работать!

Как упомянул @joe, эта функция не является методом 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;
}
var tabs = getElementsByClassName(document.body,'tab');


...Также, если вам нужна только поддержка IE8+, это будет работать:

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

Используйте его как обычно:

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

person Web_Designer    schedule 14.09.2011    source источник
comment
Вы уверены, что ваше обновление правильное? Разве это не должно быть var tabs = getElementsByClassName(document.body,'tab'); **уведомление, что я удалил document.getEle... **   -  person Anthony    schedule 23.12.2012
comment
Верны ли ваши последние примеры? Вы передаете '.tab', но разве он не должен быть без точки, так как ваш внутренний метод добавляет точку, а если это IE9+, то у него тоже нет точки? Разве это не должно быть var tabs = document.getElementsByClassName('tab');? И почему у вас есть или, когда последние два примера одинаковы? Я должен что-то упустить.   -  person BoBoCoding    schedule 21.04.2016
comment
@BoBoCoding исправлен.   -  person Web_Designer    schedule 22.04.2016
comment
См. также getElementsByClassName polyfill суть в Полифилл для getElementsByClassName для определенных целей.   -  person Vadzim    schedule 02.04.2019


Ответы (6)


Это не метод документа:

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
person Joe    schedule 14.09.2011
comment
Вы тестируете на jsFiddle.net или на своем собственном сервере/машине? - person Joe; 14.09.2011
comment
@inquisitive_web_developer — какую ошибку вы получаете сейчас? На какой линии он прерывается? - person nnnnnn; 14.09.2011

вы можете создать функцию для старых браузеров

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;
    }
}
person gdarcan    schedule 12.12.2011

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

Почти уверен, что это то же самое, что и функция Леонида, но она использует document.getElementsByClassName, когда это возможно.

person Mike_OBrien    schedule 31.10.2011

На самом деле вы не можете реплицировать getElementsByClassName, потому что он возвращает nodeList, поэтому его значение активно и обновляется вместе с документом.

Вы можете вернуть статический массив элементов с одинаковыми именами классов, но он не будет «знать», когда документ изменится.

(Не нужно слишком много таких вещей, чтобы библиотека выглядела стройной...)

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

//Пример

var A= getArrayByClassNames('sideBar local')

person kennebec    schedule 14.09.2011
comment
+1 за то, что заметил, что в отличие от настоящего getElementsByClassName, хаки совместимости (включая querySelectorAll) предоставляют статические снимки, а не живые коллекции. - person Søren Løvborg; 23.10.2013

Я просто хочу улучшить querySelectorAll запасной вариант для IE8.

Как и другие, простым способом является добавление функции в Element.prototype с помощью

this.querySelectorAll('.' + className);

Но есть некоторые проблемы:

  • Это не работает с необрезанными строками (в начале).
  • Это не работает с несколькими классами.
  • Не работает со "странными" символами класса (/, $, * и т.д.)
  • Не работает с классами, начинающимися с цифры (недопустимые идентификаторы).

Это означает, что должна быть какая-то «фиксация», например:

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

Код:

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
);
person Oriol    schedule 09.02.2014
comment
Функцию также можно добавить к HTMLDocument.prototype, чтобы использовать ее с document. - person Oriol; 15.02.2014

person    schedule
comment
Не работает в моем IE9: объект не поддерживает свойство или метод 'querySelectorAll' - person Phil; 10.09.2012