Mã với classList không hoạt động trong IE?


83

Tôi đang sử dụng mã sau, nhưng gặp lỗi trong IE. Tin nhắn là:

Không thể nhận giá trị của thuộc tính 'add': object là null hoặc undefined "

Tôi cho rằng đây chỉ là sự cố hỗ trợ của IE. Bạn sẽ làm thế nào để đoạn mã sau hoạt động trong IE?

Có ý kiến ​​gì không?

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 không có classList, do đó nó null hoặc không xác định
Esailija

2
Bạn có muốn sử dụng jQuery hay không?
arb

1
@ Zero21xxx Đừng bận tâm, nhưng điều đó sẽ yêu cầu tôi viết lại tất cả mã trên để sử dụng các đối tượng JQuery thay vì JS tiêu chuẩn.
Wesley

3
Tôi đã viết một số polyfills ở đây choclassList .
alex

1
@alex Bài đăng trên blog của bạn có thể làm được với một bản cập nhật. Đầu tiên, liên kết cuối cùng (MDN) là sai, querySelectornên được classList. Thứ hai, .removephương thức này chứa một RegExp không cần thiết, mà việc sử dụng - như bạn đã thừa nhận - sẽ tạo ra một lỗi. Bởi vì bạn đã có khoảng trắng trước và hậu tố, nên chỉ cần đơn giản .replace(' ' + className + ' ', ' ')là đủ (hơn nữa, nhận xét "Tên lớp hợp lệ không được chứa bất kỳ ký tự regex đặc biệt nào." Là không chính xác, hãy xem thông số kỹ thuật (cũng đúng với HTML4))
Rob W

Câu trả lời:


92

Các classListbất động sản không được hỗ trợ bởi IE9 và thấp hơn. IE10 + hỗ trợ nó.
Sử dụng className += " .."thay thế. Lưu ý: Không bỏ qua khoảng trắng: tên lớp nên được thêm vào danh sách được phân tách bằng khoảng trắng.

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 classNameThuộc tính luôn tồn tại. Nó được khởi tạo tại một chuỗi rỗng. Để bảo trì mã dễ dàng hơn, nên sử dụng +=để thêm tên lớp.
Rob W

2
ở chế độ nghiêm ngặt, điều này tạo ra lỗi vì className chỉ được đọc.
Jason Aller

1
@JasonAller Điều đó rất khó xảy ra, classNameThuộc tính của phần tử DOM là đọc-ghi.
Rob W

47
IE11 vẫn còn lỗi trên classList, nó không hỗ trợ classList trên phần tử SVG.
codenamezero

1
và jQuery cũng không thể thêm các lớp vào các phần tử SVG, vì vậy giải pháp từ trên có vẻ như là điều duy nhất có thể làm nếu bạn muốn thao tác SVG.
Senthe

26

Như đã đề cập bởi othes, classListkhông được hỗ trợ bởi IE9 trở lên. Cũng như sự thay thế của Alex ở trên, có một số polyfills nhằm mục đích trở thành một sự thay thế thả vào, tức là chỉ cần đưa những thứ này vào trang của bạn và IE sẽ hoạt động (từ nổi tiếng cuối cùng!).

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

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


11
Tôi đang sử dụng trình duyệt IE 11 và classList dường như không có tác dụng (công trình trong chrome)
john ktejik

1
Thật kỳ lạ - caniuse.com nói rằng nó nên được hỗ trợ từ IE10 +. Tôi khuyên bạn nên hỏi @TheWebJustWorks trên Twitter hoặc gửi vấn đề tại webcompat.com
tagawa

3
@johnktejik nếu bạn thêm hoặc xóa nhiều lớp cùng một lúc, nó sẽ không hoạt động trong IE11, Firefox 24- và Chrome 24-. Đó có phải là những gì bạn đang làm?
mnsth

1
@BradAdams Đâyđây . Caniuse và MDN cũng có báo cáo. Tuy nhiên, tất cả những vấn đề đó đã được khắc phục trong Microsoft Edge!
thứ

2
classList vẫn không được hỗ trợ trên các phần tử SVG, những polyfills này thực hiện thủ thuật
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, tuy nhiên: Tôi đã ele.getAttribute('class')trả về null trong một số trường hợp (có thể nếu thuộc tính lớp chưa được đặt?) - một câu lệnh if đơn giản đã giải quyết được vấn đề đó.
Jeppe,

8

kiểm tra cái này

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

và classList sẽ hoạt động!

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

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

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

đó là tất cả!


Tôi là một noob. Tôi đặt những thứ trên ở đâu? Trong <script> hay trong <style>?
Fandango68

Tôi đã chèn mã này vào một khối tập lệnh ngay phía trên mã vi phạm - hoạt động rất tốt. Cảm ơn.
robnick

1
Công việc tốt, tiếc là điều này không làm việc cho tôi trong mọi trường hợp, tôi đã tìm thấy cái này tuy nhiên: github.com/remy/polyfills/blob/...
Michiel

7

Trong IE 10 & 11, thuộc tính classList được định nghĩa trên HTMLElement.prototype.

Để nó hoạt động trên các phần tử SVG, thuộc tính phải được xác định trên Element.prototype, giống như nó đã có trên các trình duyệt khác.

Một bản sửa lỗi rất nhỏ sẽ là sao chép chính xác propertyDescriptor từ HTMLElement.prototype sang 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'));
    }
}
  • Chúng tôi cần sao chép bộ mô tả, vì Element.prototype.classList = HTMLElement.prototype.classListsẽ némInvalid calling object
  • Lần kiểm tra đầu tiên ngăn chặn việc ghi đè thuộc tính trên các trình duyệt vốn được hỗ trợ.
  • Kiểm tra thứ hai là ngăn lỗi trên các phiên bản IE trước 9, nơi HTMLElement chưa được triển khai và trên IE9 nơi classList chưa được triển khai.

Đối với IE 8 & 9, hãy sử dụng mã sau, tôi cũng đã bao gồm một polyfill (được rút gọn) cho Array.prototype.indexOf, vì IE 8 không hỗ trợ nó nguyên bản (nguồn 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;
    }
});

Mã đầu tiên đã cắt nó tốt, nhưng thiếu hai dấu ngoặc đóng ).
superdweebie

@superdweebie, cảm ơn bạn đã chú ý. Tôi đã sửa câu trả lời của mình
Kevin Drost

3

Trong Explorer 11 classList.add chỉ hoạt động với các giá trị duy nhất.

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

Trong trường hợp này Explorer chỉ thêm lớp đầu tiên và bỏ qua lớp thứ hai. Vì vậy, cần làm:

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

0

classListkhông được hỗ trợ trong IE <9. Sử dụng jQuery.addClass hoặc polyfill giống như tại https://developer.mozilla.org/en-US/docs/Web/API/Element/classList


1
Để ai downvoted này: đây là sự thật khi câu trả lời đã được đăng, và chỉ có IE 9 bắt đầu hỗ trợ nó
Juan Mendes

2
Tôi mạo hiểm đoán rằng nó đã bị phản đối vì câu hỏi không yêu cầu jQuery. Có nhiều cách giải quyết các vấn đề không liên quan đến việc sử dụng toàn bộ thư viện Javascript.
Vincent McNabb

4
-1: vâng .. đúng ... cho phép thêm thư viện 100KB vào classListchức năng bắt chước kém
tereško

1
@ tereško Nó nói "hoặc cái gì đó tương tự", trong trường hợp bạn chưa sử dụng jQuery. Lưu ý rằng câu trả lời được chấp nhận có thể thêm cùng một tên lớp hai lần vì nó không kiểm tra xem nó đã tồn tại hay chưa.
Juan Mendes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.