使用「classlist」简洁高效地修改元素的class属性
修改元素的class属性的通用方法是使用元素的className属性或者getAttribute和setAttribute方法,但是使用它们执行稍微复杂一些的操作都会很繁琐,HTML5提供了classList这个新的API,使得修改元素的class属性简洁高效了很多。
classList简介
元素的classList属性是一个包含该元素的class属性的只读的实时DOMTokenList实例。
元素的classList属性本身是只读的,要修改元素class属性需要使用继承自DOMTokenList原型的方法和属性,通过Object.getPrototypeOf()方法可以得到元素的classList属性的原型对象就是DOMTokenList的prototype对象。具体见下图。

从上图可以看出,在元素的classList属性上可以通过length属性获取类名的个数,还可以使用多个方法对元素的class属性进行修改。
在DOMTokenList的众多方法中,add、remove、toggle和contains方法使得修改class属性变得简洁高效。
从这几个方法的名字就能看出它们的功能,这里就不介绍了,主要说一说使用过程中的几点注意:
- 因为它们都是
DOMTokenList方法,所以参数都必须是有效的token,不能包含空格,所以无法使用HTML中class属性使用空格分隔多个类名的形式指定多个类名。 add和remove方法可以同时接受多个参数,同时处理多个类名。contains方法只接受一个参数,多余参数会被忽略。toggle接收一个参数和一个可选的布尔值参数(force),当指定force为true时,作用和add相同;当指定force为false时,作用和remove相同。- 所有方法都无法链式调用。
兼容性
classList属性的兼容性如下图。

从上图可以看出,IE又拖后腿了。在实际开发中,可以根据实际情况封装classList的不同方法。
下面简单实现了classList的add、remove、toggle和contains方法,使用了ES6特性,同时函数API和标准略有差异,只是用于演示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function classlist(el) {
let classString = el.getAttribute('class') || '';
return {
add(...classNames) {
classNames.forEach(function(className) {
if ( !this.contains(className) ) {
classString += ` ${className}`;
}
}.bind(this));
el.setAttribute('class', classString);
return this;
},
remove(...classNames) {
classNames.forEach(function(className) {
classString = classString.replace(new RegExp(className), '');
});
el.setAttribute('class', classString);
return this;
},
toggle(...classNames) {
classNames.forEach(function(className) {
this.contains(className) ? this.remove(className) : this.add(className);
}.bind(this));
return this;
},
contains(...classNames) {
return classNames.every((className) => classString.indexOf(className) !== -1);
}
};
}