DOM扩展 —— HTML5 的 CSS 类扩展

313 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

HTML4 被广泛采用以来,Web 开发中一个主要的变化是 class 属性用得越来越多,其用处是为元素添加样式以及语义信息。为了适应开发者和他们对 class 属性的认可,HTML5 增加了一些特性以方便使用 CSS 类。

1. getElementsByClassName()

getElementsByClassName()HTML5 新增的最受欢迎的一个方法,暴露在 document 对象和所有 HTML 元素上。这个方法脱胎于基于原有 DOM 特性实现该功能的 JavaScript 库,提供了性能高好的原生实现。

getElementsByClassName() 方法接收一个参数,即包含一个或多个类名的字符串,返回类名中包含相应类的元素的 NodeList。如果提供了多个类名,则顺序无关紧要。下面是几个示例:

// 取得所有类名中包含"username"和"current"元素
// 这两个类名的顺序无关紧要
let allCurrentUsernames = document.getElementsByClassName("username current");
// 取得 ID 为"myDiv"的元素子树中所有包含"selected"类的元素
let selected = document.getElementById("myDiv").getElementsByClassName("selected");

如果要给包含特定类(而不是特定 ID 或标签)的元素添加事件处理程序,使用这个方法会很方便。不过要记住,因为返回值是 NodeList,所以使用这个方法会遇到跟使用 getElementsByTagName() 和其他返回 NodeList 对象的 DOM 方法同样的问题。

2. classList 属性

要操作类名,可以通过 className 属性实现添加、删除和替换。但 className 是一个字符串,所以每次操作之后都需要重新设置这个值才能生效,即使只改动了部分字符串也一样。以下面的 HTML 代码为例:

<div class="bd user disabled">...</div>

这个 <div> 元素有 3 个类名。要想删除其中一个,就得先把 className 拆开,删除不想要的那个,再把包含剩余类的字符串设置回去。比如:

// 要删除"user"类
let targetClass = "user";
// 把类名拆成数组
let classNames = div.className.split(/\s+/);
// 找到要删除类名的索引
let idx = classNames.indexOf(targetClass);
// 如果有则删除
if (idx > -1) {
 classNames.splice(i,1);
}
// 重新设置类名
div.className = classNames.join(" ");

HTML5 通过给所有元素增加 classList 属性为这些操作提供了更简单也更安全的实现方式。classList 是一个新的集合类型 DOMTokenList 的实例。与其他 DOM 集合类型一样,DOMTokenList 也有 length 属性表示自己包含多少项,也可以通过 item() 或中括号取得个别的元素。此外,DOMTokenList 还增加了以下方法。

  • add(value),向类名列表中添加指定的字符串值 value。如果这个值已经存在,则什么也不做。
  • contains(value),返回布尔值,表示给定的 value 是否存在。
  • remove(value),从类名列表中删除指定的字符串值 value
  • toggle(value),如果类名列表中已经存在指定的 value,则删除;如果不存在,则添加。
  • replace(old, new),如果类名列表中已经存在指定的 old,则替换成 new;如果不存在,则什么也不做。

这样以来,前面的例子中那么多行代码就可以简化成下面的一行:

div.classList.remove("user"); 

这行代码可以在不影响其他类名的情况下完成删除。其他方法同样极大地简化了操作类名的复杂性,如下面的例子所示:

// 删除"disabled"类
div.classList.remove("disabled");
// 添加"current"类
div.classList.add("current");
// 切换"user"类
div.classList.toggle("user");
// 检测类名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){
 // 执行操作
)
// 迭代类名
for (let class of div.classList){
 doStuff(class);
}
// 将类值 "foo" 替换成 "bar"
div.classList.replace("foo", "bar");

添加了 classList 属性之后,除非是完全删除或完全重写元素的 class 属性,否则 className属性就用不到了。

引用