classList가있는 코드가 IE에서 작동하지 않습니까?


83

다음 코드를 사용하고 있지만 IE에서 실패합니다. 메시지는 다음과 같습니다.

속성 'add'의 값을 가져올 수 없습니다. 개체가 null이거나 정의되지 않았습니다. "

나는 이것이 단지 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);


2
jQuery를 사용 하시겠습니까?
arb

1
@ Zero21xxx 괜찮습니다.하지만 표준 JS 대신 JQuery 객체를 사용하려면 위의 모든 코드를 다시 작성해야합니다.
Wesley


1
@alex 블로그 게시물은 업데이트로 할 수 있습니다. 첫째, 마지막 링크 (MDN)이 잘못, querySelector해야한다 classList. 둘째,이 .remove메서드에는 불필요한 RegExp가 포함되어 있습니다. 이 메서드를 사용하면-당신이 알고 있듯이-버그가 발생합니다. 이미 공백을 사전 및 접미사로 지정 했으므로 간단 .replace(' ' + className + ' ', ' ')해도 충분합니다 (또한 "유효한 클래스 이름에는 특수 정규식 문자를 포함해서는 안됩니다."라는 설명 이 올바르지 않습니다 . 사양 참조 (HTML4에도 해당))
Rob W

답변:


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속성은 항상 존재합니다. 빈 문자열에서 초기화됩니다. 보다 쉬운 코드 유지 관리를 +=위해를 사용 하여 클래스 이름을 추가하는 것이 좋습니다.
Rob W

2
엄격 모드에서는 className이 읽기 전용이므로 오류가 발생합니다.
Jason Aller 2014

1
@JasonAller 거의 불가능 className합니다. DOM 요소 의 속성은 읽기-쓰기입니다.
Rob W

47
IE11은 여전히 ​​classList의 버그이며 SVG 요소의 classList를 지원하지 않습니다.
codenamezero

1
jQuery는 SVG 요소에도 클래스를 추가 할 수 없으므로 위의 솔루션은 SVG를 조작하려는 경우에만 가능한 것처럼 보입니다.
Senthe

26

othes에서 언급했듯이 classListIE9 및 이전 버전에서는 지원되지 않습니다. 위의 Alex의 대안과 마찬가지로 드롭 인 교체를 목표로하는 두 개의 polyfill이 있습니다.

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

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


11
IE 11을 사용하고 있으며 classList가 작동하지 않는 것 같습니다 (크롬에서 작동)
john ktejik

1
이상합니다. caniuse.com은 IE10 +에서 지원되어야한다고 말합니다. 나는 트위터에 @TheWebJustWorks 요청 또는에서 문제를 제기하는 것이 좋습니다 webcompat.com
타가

3
@johnktejik 한 번에 여러 클래스를 추가하거나 제거하면 IE11, Firefox 24 및 Chrome 24에서 작동하지 않습니다. 그게 당신이하는 일 이었나요?
mnsth

1
@BradAdams 여기여기 . Caniuse와 MDN에도 보고서가 있습니다. 그러나 이러한 모든 문제는 Microsoft Edge에서 수정되었습니다!
mnsth

2
classList는 여전히 SVG 요소에서 지원되지 않습니다. 이러한 polyfill은 트릭을 수행합니다
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을 반환했습니다 (아직 클래스 속성이 설정되지 않은 경우 일 수 있습니까?)-간단한 if 문으로 해결되었습니다.
Jeppe

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 2015 년

이 코드를 문제가되는 코드 바로 위의 스크립트 블록에 삽입했습니다. 매우 잘 작동합니다. 감사.
robnick


7

IE 10 및 11에서 classList 속성은 HTMLElement.prototype에 정의되어 있습니다.

SVG 요소에서 작동하게하려면 속성이 다른 브라우저 에서처럼 Element.prototype에 정의되어야합니다.

아주 작은 수정은 HTMLElement.prototype에서 Element.prototype으로 정확한 propertyDescriptor를 복사하는 것입니다.

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
  • 첫 번째 확인은 기본적으로 지원되는 브라우저에서 속성을 덮어 쓰는 것을 방지합니다.
  • 두 번째 검사는 HTMLElement가 아직 구현되지 않은 9 이전 IE 버전과 classList가 구현되지 않은 IE9에서 오류를 방지하는 것입니다.

IE 8 및 9의 경우 다음 코드를 사용하고, IE 8에서 기본적으로 지원하지 않기 때문에 Array.prototype.indexOf에 대한 (축소 된) 폴리 필도 포함했습니다 (폴리 필 소스 : 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

@superdweebie, 알아 주셔서 감사합니다. 나는 내 대답을 해결했습니다
케빈 Drost을

3

Explorer 11에서 classList.add는 단일 값으로 만 작동합니다.

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

이 경우 Explorer는 첫 번째 클래스 만 추가하고 두 번째 클래스는 무시합니다. 따라서 다음을 수행해야합니다.

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

0

classListIE <9에서는 지원되지 않습니다. jQuery.addClass 또는 https://developer.mozilla.org/en-US/docs/Web/API/Element/classList에 있는 것과 같은 polyfill을 사용 하십시오.


1
이을 downvoted 누구든지 : 대답을 게시 한 경우이 사실, 오직 IE 9는 지원 시작
후안 멘데스

2
질문이 jQuery를 요구하지 않았기 때문에 투표가 거부 된 것으로 추측 할 수 있습니다. 전체 자바 스크립트 라이브러리를 사용하지 않는 문제를 해결하는 방법이 있습니다.
Vincent McNabb 2014

4
-1 : 그래 .. 바로 ... 심하게 모방에 추가 1백킬로바이트 라이브러리를 할 수 있습니다 classList기능
tereško

1
@ tereško 이미 jQuery를 사용하고 있지 않은 경우 "또는 이와 비슷한"이라고 표시됩니다. 수락 된 답변은 이미 존재하는지 확인하지 않기 때문에 동일한 클래스 이름을 두 번 추가 할 수 있습니다.
Juan Mendes 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.