Код із classList не працює в IE?


83

Я використовую наступний код, але його помилка в IE. Повідомлення:

Не вдалося отримати значення властивості 'add': об'єкт нульовий або невизначений "

Я припускаю, що це лише проблема підтримки IE. Як би ви змусили наступний код працювати в IE?

Будь-які ідеї?

var img = new Image();
img.src = '/image/file.png';
img.title = 'this is a title';
img.classList.add("profilePic");
var div = document.createElement("div");
div.classList.add("picWindow");
div.appendChild(img);
content.appendChild(div);

5
IE не має списку класів, отже, він є нульовим або невизначеним
Esailija,

2
Ви хочете використовувати jQuery чи ні?
arb

1
@ Zero21xxx Не заперечуйте, але це зажадає від мене переписування всього вищезазначеного коду для використання об'єктів JQuery замість стандартних JS.
Wesley

3
Я написав тутclassList кілька поліфілів .
alex

1
@alex Ваш допис у блозі може стосуватися оновлення. По-перше, кінцеве посилання (MDN) неправильне, querySelectorповинно бути classList. По-друге, .removeметод містить непотрібний RegExp, використання якого - як ви визнали - вносить помилку. Оскільки ви вже мали попередні та суфіксовані пробіли, достатньо простого .replace(' ' + className + ' ', ' ')(крім того, зауваження "Дійсне ім'я класу не повинно містити спеціальних символів регулярних виразів." Є неправильним, див. Специфікацію (також стосується HTML4))
Роб В

Відповіді:


92

classListВластивість не підтримується IE9 і нижче. IE10 + це підтримує.
Використовуйте className += " .."замість цього. Примітка: Не пропускайте пробіл: імена класів слід додавати в розділений пробілами список.

var img = new Image();
img.src = '/image/file.png';
img.title = 'this is a title';
img.className += " profilePic"; // Add profilePic class to the image

var div = document.createElement("div");
div.className += " picWindow";  // Add picWindow class to the div
div.appendChild(img);
content.appendChild(div);

3
@MikeChristensen classNameАтрибут існує завжди. Він ініціалізується порожнім рядком. Для зручності обслуговування коду рекомендується використовувати +=для додавання назв класів.
Роб W

2
в суворому режимі це генерує помилку, оскільки className є лише для читання.
Джейсон Аллер

1
@JasonAller Це малоймовірно, classNameвластивість елемента DOM - це читання-запис.
Роб W

47
IE11 все ще помилка в classList, він не підтримує classList для елемента SVG.
codenamezero

1
а jQuery також не може додавати класи до елементів SVG, тому рішення зверху виглядає лише можливим, якщо ви хочете маніпулювати SVG.
Senthe

26

Як згадували інші, classListне підтримується IE9 та старшими версіями. Окрім вищезазначеної альтернативи Алекса, є кілька поліфілів, які мають на меті замінити їх, тобто просто включіть їх на свою сторінку, і IE повинен просто працювати (відомі останні слова!)

https://github.com/eligrey/classList.js/blob/master/classList.js

https://gist.github.com/devongovett/1381839


11
Я використовую IE 11, і classList, здається, не працює (працює в chrome)
Джон Ктеджік,

1
Це дивно - caniuse.com каже, що його слід підтримувати з IE10 +. Пропоную запитати @TheWebJustWorks у Twitter або подати проблему на webcompat.com
tagawa

3
@johnktejik, якщо ви додаєте або видаляєте кілька класів одночасно, це не буде працювати в IE11, Firefox 24- та Chrome 24-. Ти цим займався?
mnsth

1
@BradAdams Тут і тут . Caniuse та MDN також мають звіти. Однак усі ці проблеми виправлені в Microsoft Edge!
mnsth

3
ClassList ще не підтримується на елементах SVG, ця polyfills зробити трюк
Shoplifter.Doe

10
    /**
 * Method that checks whether cls is present in element object.
 * @param  {Object} ele DOM element which needs to be checked
 * @param  {Object} cls Classname is tested
 * @return {Boolean} True if cls is present, false otherwise.
 */
function hasClass(ele, cls) {
    return ele.getAttribute('class').indexOf(cls) > -1;
}

/**
 * Method that adds a class to given element.
 * @param  {Object} ele DOM element where class needs to be added
 * @param  {Object} cls Classname which is to be added
 * @return {null} nothing is returned.
 */
function addClass(ele, cls) {
    if (ele.classList) {
        ele.classList.add(cls);
    } else if (!hasClass(ele, cls)) {
        ele.setAttribute('class', ele.getAttribute('class') + ' ' + cls);
    }
}

/**
 * Method that does a check to ensure that class is removed from element.
 * @param  {Object} ele DOM element where class needs to be removed
 * @param  {Object} cls Classname which is to be removed
 * @return {null} Null nothing is returned.
 */
function removeClass(ele, cls) {
    if (ele.classList) {
        ele.classList.remove(cls);
    } else if (hasClass(ele, cls)) {
        ele.setAttribute('class', ele.getAttribute('class').replace(cls, ' '));
    }
}

2
+1, однак: ele.getAttribute('class')у деяких випадках у мене було повернення null (можливо, якщо атрибут class ще не встановлений?) - простий оператор if це вирішив.
Джеппе,

8

Перевір це

Object.defineProperty(Element.prototype, 'classList', {
    get: function() {
        var self = this, bValue = self.className.split(" ")

        bValue.add = function (){
            var b;
            for(i in arguments){
                b = true;
                for (var j = 0; j<bValue.length;j++)
                    if (bValue[j] == arguments[i]){
                        b = false
                        break
                    }
                if(b)
                    self.className += (self.className?" ":"")+arguments[i]
            }
        }
        bValue.remove = function(){
            self.className = ""
            for(i in arguments)
                for (var j = 0; j<bValue.length;j++)
                    if(bValue[j] != arguments[i])
                        self.className += (self.className?" " :"")+bValue[j]
        }
        bValue.toggle = function(x){
            var b;
            if(x){
                self.className = ""
                b = false;
                for (var j = 0; j<bValue.length;j++)
                    if(bValue[j] != x){
                        self.className += (self.className?" " :"")+bValue[j]
                        b = false
                    } else b = true
                if(!b)
                    self.className += (self.className?" ":"")+x
            } else throw new TypeError("Failed to execute 'toggle': 1 argument required")
            return !b;
        }

        return bValue; 
    },
    enumerable: false
})

і classList буде працювати!

document.getElementsByTagName("div")[0].classList
["aclass"]

document.getElementsByTagName("div")[0].classList.add("myclass")

document.getElementsByTagName("div")[0].className
"aclass myclass"

це все!


Я нуб. Де я можу розмістити вищезазначене? У <script> або в <style>?
Fandango68

Я вставив цей код у блок сценарію безпосередньо над порушуючим кодом - працює дуже добре. Дякую.
Робнік

1
Хороша робота, на жаль, це не працює у мене у всіх випадках, я все-таки знайшов це: github.com/remy/polyfills/blob/…
Michiel

8

В IE 10 і 11 властивість classList визначається на HTMLElement.prototype.

Для того, щоб змусити його працювати над SVG-елементами, властивість слід визначити на Element.prototype, як це було в інших браузерах.

Дуже невеликим виправленням було б копіювання точного властивостіDescriptor з HTMLElement.prototype до Element.prototype:

if (!Object.getOwnPropertyDescriptor(Element.prototype,'classList')){
    if (HTMLElement&&Object.getOwnPropertyDescriptor(HTMLElement.prototype,'classList')){
        Object.defineProperty(Element.prototype,'classList',Object.getOwnPropertyDescriptor(HTMLElement.prototype,'classList'));
    }
}
  • Нам потрібно скопіювати дескриптор, оскільки Element.prototype.classList = HTMLElement.prototype.classListбуде кидатиInvalid calling object
  • Перша перевірка запобігає перезапису властивості у браузерах, які підтримують спочатку.
  • Друга перевірка - запобігає помилкам у версіях IE до 9, де HTMLElement ще не реалізований, та в IE9, де classList не реалізований.

Для IE 8 і 9 використовуйте такий код, я також включив (зменшений) поліфіл для Array.prototype.indexOf, оскільки IE 8 не підтримує його спочатку (джерело polyfill : Array.prototype.indexOf

//Polyfill Array.prototype.indexOf
Array.prototype.indexOf||(Array.prototype.indexOf=function (value,startIndex){'use strict';if (this==null)throw new TypeError('array.prototype.indexOf called on null or undefined');var o=Object(this),l=o.length>>>0;if(l===0)return -1;var n=startIndex|0,k=Math.max(n>=0?n:l-Math.abs(n),0)-1;function sameOrNaN(a,b){return a===b||(typeof a==='number'&&typeof b==='number'&&isNaN(a)&&isNaN(b))}while(++k<l)if(k in o&&sameOrNaN(o[k],value))return k;return -1});

// adds classList support (as Array) to Element.prototype for IE8-9
Object.defineProperty(Element.prototype,'classList',{
    get:function(){
        var element=this,domTokenList=(element.getAttribute('class')||'').replace(/^\s+|\s$/g,'').split(/\s+/g);
        if (domTokenList[0]==='') domTokenList.splice(0,1);
        function setClass(){
            if (domTokenList.length > 0) element.setAttribute('class', domTokenList.join(' ');
            else element.removeAttribute('class');
        }
        domTokenList.toggle=function(className,force){
            if (force!==undefined){
                if (force) domTokenList.add(className);
                else domTokenList.remove(className);
            }
            else {
                if (domTokenList.indexOf(className)!==-1) domTokenList.splice(domTokenList.indexOf(className),1);
                else domTokenList.push(className);
            }
            setClass();
        };
        domTokenList.add=function(){
            var args=[].slice.call(arguments)
            for (var i=0,l=args.length;i<l;i++){
                if (domTokenList.indexOf(args[i])===-1) domTokenList.push(args[i])
            };
            setClass();
        };
        domTokenList.remove=function(){
            var args=[].slice.call(arguments)
            for (var i=0,l=args.length;i<l;i++){
                if (domTokenList.indexOf(args[i])!==-1) domTokenList.splice(domTokenList.indexOf(args[i]),1);
            };
            setClass();
        };
        domTokenList.item=function(i){
            return domTokenList[i];
        };
        domTokenList.contains=function(className){
            return domTokenList.indexOf(className)!==-1;
        };
        domTokenList.replace=function(oldClass,newClass){
            if (domTokenList.indexOf(oldClass)!==-1) domTokenList.splice(domTokenList.indexOf(oldClass),1,newClass);
            setClass();
        };
        domTokenList.value = (element.getAttribute('class')||'');
        return domTokenList;
    }
});

Перший код добре його вирізав, але бракує двох заключних дужок ).
superdweebie 01.03.18

@superdweebie, дякую, що помітили. Я виправив свою відповідь
Кевін Дрост

3

У Провіднику 11 classList.add працює лише з одними значеннями.

Element.classList.add("classOne", "classTwo");

У цьому випадку Explorer додає лише перший клас, а другий ігнорує. Тому потрібно зробити:

Element.classList.add("classOne");
Element.classList.add("classTwo");

0

classListне підтримується в IE <9. Використовуйте jQuery.addClass або поліфіл, подібний до того, що розміщений на https://developer.mozilla.org/en-US/docs/Web/API/Element/classList


1
Для тих, хто голосував проти цього: це було правдою, коли була опублікована відповідь, і лише IE 9 почав її підтримувати
Хуан Мендес

2
Я ризикую здогадатися, що це було проти, тому що питання не вимагало jQuery. Існують способи обійти проблеми, які не пов’язані з використанням цілої бібліотеки Javascript.
Вінсент Мак-Набб

4
-1: так .. так ... дозволяє додати 100 Кб бібліотеки для погано імітують classListфункціональність
tereško

1
@ tereško У ньому написано "або щось подібне", якщо ви ще не використовуєте jQuery. Зверніть увагу, що прийнята відповідь може додати одне і те ж ім’я класу двічі, оскільки воно не перевіряє, чи воно вже існує.
Хуан Мендес,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.