带有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);

5
IE没有classList,因此它为null或未定义
Esailija

2
您是否要使用jQuery?
ARB

1
@ Zero21xxx不必介意,但这需要我重写以上所有代码以使用JQuery对象而不是标准JS。
韦斯利

3
在这里classList写了一些polyfills
alex

1
@alex您的博客文章可以进行更新。首先,最终链接(MDN)错误,querySelector应该为classList。其次,该.remove方法包含不必要的RegExp,如您所知,它的用法会引入错误。因为您已经有前置和后缀空格,所以简单.replace(' ' + className + ' ', ' ')就足够了(此外,“有效的className不应包含任何特殊的正则表达式字符。”这是不正确的,请参见spec(对于HTML4也是如此))
Rob W

Answers:


92

classListIE9及更低版本不支持该属性。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是只读的。
杰森·艾勒2014年

1
@JasonAller这是不太可能的,classNameDOM元素的属性是可读写的。
罗布W

47
IE11在classList上仍然存在错误,它不支持SVG元素上的classList。
codenamezero

1
而且jQuery也无法将类添加到SVG元素,因此,从上开始的解决方案似乎仅是您想操作SVG时可以做的事情。
Senthe

26

如othes所述,classListIE9和更早版本不支持。除了上述Alex的替代方案之外,还有一些polyfill旨在作为即插即用的替代方案,即仅将它们包含在您的页面中,IE应该可以正常工作(著名的最后一句话!)。

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

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


11
我使用的是IE 11,classList似乎无法正常运行(在Chrome中运行)
john ktejik 2014年

1
真奇怪-caniuse.com说它应该得到IE10 +的支持。我建议,要求在Twitter @TheWebJustWorks或备案的问题webcompat.com
田川

3
@johnktejik如果您一次添加或删除多个类,它将无法在IE11,Firefox 24-和Chrome 24-中运行。那是你在做什么吗?
mnsth,2015年

1
@BradAdams在这里这里。Caniuse和MDN也有报告。不过,所有这些问题都已在Microsoft Edge中修复!
mnsth

2
SVG元素仍不支持classList,这些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')在某些情况下(如果尚未设置class属性,我已经返回了null)-一个简单的if语句解决了它。
Jeppe '18年

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年

我将此代码插入到有问题的代码上方的脚本块中,效果非常好。谢谢。
罗宾尼克'16

1
好的工作,不幸的是,这在所有情况下都不适合我,但是我确实找到了一个:github.com/remy/polyfills/blob/…–
Michiel

7

在IE 10和11中,classList属性在HTMLElement.prototype上定义。

为了使其能够在SVG元素上运行,应在Element.prototype上定义该属性,就像在其他浏览器上一样。

一个非常小的修复是将确切的propertyDescriptor从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
  • 第一次检查可防止覆盖本机支持的浏览器上的属性。
  • 第二项检查是防止在9之前的IE版本(尚未实现HTMLElement)和IE9的错误(尚未实现classList)上发生错误。

对于IE 8和9,请使用以下代码,我还为Array.prototype.indexOf提供了一个(最小化的)polyfill,因为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

@superdweebie,感谢您的注意。我已经解决了我的问题
Kevin Drost

3

在资源管理器11中,classList.add仅适用于单个值。

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

在这种情况下,资源管理器仅添加第一类,而忽略第二类。所以需要做:

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
对于任何对此表示不满的人:答案发布时都是如此,只有IE 9开始支持它
Juan Mendes

2
我可能会猜测它被否决了,因为该问题并未要求使用jQuery。有一些方法可以解决不涉及使用整个Javascript库的问题。
Vincent McNabb 2014年

4
-1:是啊..正确的......让我们来添加100KB库要差些模拟classList功能
tereško

1
@tereško如果您还没有使用jQuery,它会说“或类似的东西”。请注意,接受的答案可能会两次添加相同的类名,因为它不会检查是否已经存在。
Juan Mendes 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.