修改元素的class属性的通用方法是使用元素的className属性或者getAttributesetAttribute方法,但是使用它们执行稍微复杂一些的操作都会很繁琐,HTML5提供了classList这个新的API,使得修改元素的class属性简洁高效了很多。

classList简介

元素的classList属性是一个包含该元素的class属性的只读实时DOMTokenList实例。

元素的classList属性本身是只读的,要修改元素class属性需要使用继承自DOMTokenList原型的方法和属性,通过Object.getPrototypeOf()方法可以得到元素的classList属性的原型对象就是DOMTokenList的prototype对象。具体见下图。

DOMTokenList

从上图可以看出,在元素的classList属性上可以通过length属性获取类名的个数,还可以使用多个方法对元素的class属性进行修改。

在DOMTokenList的众多方法中,addremovetogglecontains方法使得修改class属性变得简洁高效。

从这几个方法的名字就能看出它们的功能,这里就不介绍了,主要说一说使用过程中的几点注意:

  • 因为它们都是DOMTokenList方法,所以参数都必须是有效的token,不能包含空格,所以无法使用HTML中class属性使用空格分隔多个类名的形式指定多个类名。
  • addremove方法可以同时接受多个参数,同时处理多个类名。
  • contains方法只接受一个参数,多余参数会被忽略。
  • toggle接收一个参数和一个可选的布尔值参数(force),当指定forcetrue时,作用和add相同;当指定forcefalse时,作用和remove相同。
  • 所有方法都无法链式调用。

兼容性

classList属性的兼容性如下图。

classList兼容性

从上图可以看出,IE又拖后腿了。在实际开发中,可以根据实际情况封装classList的不同方法。

下面简单实现了classListaddremovetogglecontains方法,使用了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);
    }
  };
}

参考

MDN Element.classList

MDN DOMTokenList