1. classList 的基本用法
1.1 定义与作用
classList 是 Elements 的一个只读属性,返回一个 DOMTokenList 对象,专门用于管理当前元素的 class 集合。与直接操作 className 字符串相比,使用 classList 可以避免手动拼接和分割字符串带来的错误,提升代码可读性和健壮性。
通过 classList,可以对当前元素的 CSS 类进行增删查改且保持状态同步。它封装了对 class 的操作,使你无需担心空格、重复类名等常见问题,从而提升开发效率与代码可维护性。
// 获取元素
const btn = document.querySelector('#btn');
/* 通过 classList 来检查、添加、删除类 */
if (btn.classList.contains('active')) {btn.classList.remove('active');
}
btn.classList.add('active', 'focus');
1.2 常用方法概览
add() 可以一次添加一个或多个类名,传入的参数是一个或多个字符串标识的 tokens,不会覆盖已有类,只是追加。如需同时添加多个类,这种写法特别方便。
remove() 同样支持一次移除一个或多个 token。如果某个 token 不存在,不会抛出错误,直接忽略即可,这使得清理状态更加稳健。
const el = document.querySelector('.box');
el.classList.add('visible', 'highlight'); // 添加多类
el.classList.remove('hidden', 'fade'); // 移除多类
contains() 用于判断元素是否包含某个 class,返回布尔值 true 或 false,在条件判断和逻辑分支中非常有用。
if (el.classList.contains('active')) {// 做一些操作
}
2. 高级用法与注意点
2.1 toggle 的强制参数
toggle() 除了单参数用法外,还支持第二个参数 force,用于强制添加或移除某个 class。当 force 为 true 时,会确保该 class 保持存在;为 false 时,会将其移除。该形式在状态切换控件中非常实用,且返回值为布尔值,表示操作后的存在状态。
使用场景示例:通过一个布尔变量控制某个 UI 状态的开关,简化了条件判断逻辑,同时保持代码简洁。
const panel = document.querySelector('#panel');
const isOpen = true; // 例如某个状态变量
panel.classList.toggle('open', isOpen); // 当 isOpen 为 true 时加入 open;否则移除
2.2 同时操作多类名
add() 与 remove() 支持一次传入多个 tokens,除了提升可读性外,还能减少多次 DOM 访问,降低性能开销。
对于需要同时应用多组样式的场景,可以把相关 class 一次性追加或清理,以确保状态一致性与视觉效果的同步。
const item = document.querySelector('.item');
item.classList.add('selected', 'enabled', 'shadow');
item.classList.remove('hidden', 'disabled');
contains() 在结合条件渲染时也很有帮助,可以快速判断是否已经包含某个视觉状态。
2.3 与 CSS 选择器的关系
通过 classList 改变的其实是元素的 class 属性,进而驱动 CSS 的选择器规则(例如 .btn.active 或 .card:hover 的样式)。需要注意的是,classList 不能直接操作伪类如 :hover、:focus,而是通过切换具体的 class 来间接影响伪类对应的样式。
因此,合理的做法是将状态抽象为一个或多个明确的 class,然后在 CSS 中用选择器表达各状态的样式。这样可以实现样式与状态的清晰分离,也便于复用与维护。
3. 实战示例:常见前端场景中的应用
3.1 菜单切换与可访问性
在导航菜单中,点击按钮时通过 classList.toggle 来切换展开状态,并配合 aria-expanded 属性实现可访问性(a11y)。这种方式使屏幕阅读器可以正确解读当前菜单的展开状态。
实际实现思路:按钮点击后将导航容器的 open 类切换,并同步更新 aria-expanded 的布尔值,确保无障碍用户体验的一致性。
const btn = document.querySelector('.menu-btn');
const nav = document.querySelector('.nav');
btn.addEventListener('click', () => {const isOpen = !nav.classList.contains('open');nav.classList.toggle('open', isOpen);btn.setAttribute('aria-expanded', String(isOpen));
});
3.2 表单校验与视觉反馈
在表单校验场景中,通过 classList 切换 is-valid 与 is-invalid 等状态类,实现实时的视觉反馈与一致的样式定义。
结合 HTML5 表单校验 API,可以在用户输入时动态更新样式,提升使用体验,并保持代码脉络清晰。
const input = document.querySelector('#email');
input.addEventListener('input', () => {if (input.checkValidity()) {input.classList.add('is-valid');input.classList.remove('is-invalid');} else {input.classList.add('is-invalid');input.classList.remove('is-valid');}
});
3.3 动态创建元素并应用样式
在运行时动态创建 DOM 节点时,可以通过 classList 直接为新元素分配初始状态。例如创建一个列表项并设置选中状态,以及后续的交互样式。
通过在创建阶段就添加所需的 class,可以减少后续的 DOM 操作次数,让渲染路径更加高效。
const ul = document.querySelector('#list');
for (let i = 0; i < 5; i++) {const li = document.createElement('li');li.classList.add('item');if (i === 0) li.classList.add('selected');ul.appendChild(li);
}
4. 常见坑与兼容性
4.1 浏览器兼容性与回退方案
在主流浏览器中,classList 得到广泛支持,IE10 及以上版本 已原生支持该特性。对于需要覆盖极旧浏览器的项目,可以考虑使用 polyfill 或者回退到对 className 的直接操作。
如果你需要在不支持的环境中兜底,可以在入口处做一个简单检测:若 classList 不可用,则使用原始的 className 操作替代。这样可以确保核心交互在不同环境都有可用路径。

if (!('classList' in document.documentElement)) {// 简易回退实现:仅示意,实际可结合需求实现替换逻辑Element.prototype.addClass = function(cls) {this.className += ' ' + cls;};
}
4.2 性能与开发习惯
在高频触发的场景中,尽量通过 classList 批量更新来减少 DOM 访问次数,并避免对 innerHTML 或大范围字符串拼接的频繁操作,以降低重排和重绘成本。
养成把状态抽象成可复用的类名的习惯,可以提升团队协作效率,同时让 CSS 组织更具可维护性。


