Код із 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.