JS 删除 class 的方法

给元素加 class 谁都会,删的时候问题就多了:删一个还是删多个?元素有多个 class 时会不会误删?老项目里还要兼容 IE。这里把几种写法都过一遍。

一、classList.remove:现代浏览器首选

const el = document.getElementById('box');

// 删一个
el.classList.remove('active');

// 删多个
el.classList.remove('active', 'show', 'disabled');

classList 是 DOMTokenList 对象,remove 支持一次传多个参数,不存在的 class 不会报错,静默忽略。这个特性比字符串替换安全得多。

classList 的其他方法:

el.classList.add('active');        // 添加
el.classList.toggle('active');     // 有则删,无则加
el.classList.contains('active');   // 是否包含
el.classList.replace('old', 'new');// 替换

注意 classList 的值是只读的集合,不能直接赋值,el.classList = 'xxx' 无效。

二、className:字符串操作

// 直接覆盖,会清掉其他所有 class
el.className = '';

// 保留部分 class
el.className = 'box active';

className 是字符串,赋值会完全替换。想删除其中一个,得自己处理字符串:

el.className = el.className
  .split(' ')
  .filter(c => c !== 'active')
  .join(' ');

麻烦但兼容性最好,IE8 及以下也能跑。注意多个空格会产生空字符串项,filter 时顺手去掉。

三、setAttribute / removeAttribute

el.removeAttribute('class');  // 整个 class 属性删掉
el.setAttribute('class', 'box');  // 重设

removeAttribute('class') 和 el.className = '' 效果差不多,都会让元素没有 class 属性。区别是前者连属性名都移除,后者会留一个空属性。视觉上没差别,但用 CSS 属性选择器 [class] 时行为不同。

四、jQuery 写法

$('#box').removeClass('active');
$('#box').removeClass('active show');  // 空格分隔删多个
$('#box').removeClass();               // 清空所有 class

removeClass 不带参数会清空全部,这点和原生不一样,容易误用。jQuery 3.x 之后内部也是走 classList,性能差不多。

五、几个容易踩的坑

1. 元素不存在

document.querySelector('.not-exist').classList.remove('x');
// TypeError: Cannot read properties of null

先判空再操作,尤其是异步渲染的页面,元素可能还没生成。

2. SVG 元素的 classList

老版本浏览器里 SVG 的 className 是 SVGAnimatedString 对象,不是字符串,直接拼字符串会得到 "[object SVGAnimatedString]"。用 classList 就没这个问题,或者用 getAttribute('class')。

3. 多个元素

// querySelectorAll 返回 NodeList,不能直接调 classList
document.querySelectorAll('.item').forEach(el => {
  el.classList.remove('active');
});

NodeList 在旧浏览器里没有 forEach,转数组:Array.prototype.forEach.call(list, fn)。

4. 删除后样式没变

可能是 CSS 里用了更高优先级的选择器,或者 class 名拼错了。也可能是元素上有内联 style 覆盖了 class 的样式,删 class 不影响内联样式。

5. 动画过渡失效

删除 class 触发 transition 时,如果元素刚被插入 DOM 就立刻删,浏览器还没完成首次渲染,过渡不会执行。需要 requestAnimationFrame 或者 setTimeout 延迟一帧。

六、场景示例

切换选中状态

document.querySelectorAll('.tab').forEach(tab => {
  tab.addEventListener('click', () => {
    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
    tab.classList.add('active');
  });
});

先全部清掉,再给当前加,这是最不容易出错的写法。用 toggle 反而会出现多个同时选中。

关闭弹窗

function closeModal() {
  const modal = document.querySelector('.modal');
  if (!modal) return;
  modal.classList.remove('show');
  // 等动画结束再隐藏
  setTimeout(() => modal.classList.remove('open'), 300);
}

批量清理

// 清掉所有状态类
['active', 'show', 'error', 'loading'].forEach(c => el.classList.remove(c));

比写四行 remove 更简洁,也方便以后加新的状态类。