超详细的jQuery和纯js实现addClass、removeClass方法

2,980 阅读4分钟

需求描述

<!--给下面的div添加 class2,可以删除class1-->
<div id="div1" class="class1"></div>

一、Jquery方法

Jquery 中 addClass 与 removeClass 是两个使用高频的方法,对于为 dom 元素增删 class 类非常方便。

$("#div1").addClass("class2");
$("#div1").removeClass("class1");

二、 操作 classList 属性

我们随便获取一个dom对象,打印(console.dir())出它的对象属性,可以看到管理 class 类的主要有 classList 属性与 className 属性。 classList

1. classList属性

classList 属性的值为 DOMTokenList 对象,关于DOMTokenList官方解释是一组空格分隔的标记,与Array一样具有 length 属性,且索引从0开始,但无法使用 Array 对象的方法。

不过 DOMTokenList 对象内置了 add,remove,contains 等方法,用于增删改查等操作;所以我们可以使用add,remove 像JQ中 addClass 与 removeClass 方法一样操作 class 类。

let div = document.getElementById('div1');
div.classList.add("class2");
div.classList.remove("class1");

2.classList兼容问题

我们发现这两个方法用的很爽啊,跟JQ一样,一个方法解决class类的操作,但比较遗憾的是,这两个方法均存在兼容问题: img 虽然其它浏览器兼容性良好,但铁打的IE从9之前完全不支持classList属性,从版本10开始支持该属性,但不支持 add 与 remove 方法。

所以说如果要兼容IE,此做法不可取,但如果不用考虑IE,那就真的能像JQ一样使用便捷了。

三、操作 className 属性

1.className 与 classList 的区别

说完 classList 属性,我们再考虑从 className 下手;className 属性与 classList 属性同为 Dom 属性且都管理 class 类的值,不同的是 classLis t属性值为特殊的 DOMTokenList 对象,而 className 属性的值为普通的字符串。

我们尝试自定义一个有class类的元素,分别获取两者的值:

<div id="div1" class="demo1 demo2"></div>
demo1
demo1

2.用js模拟实现

那要从 className 属性入手来操作class类,无非就是字符串的拼接截取操作了,这里就直接附上代码:

//自定义添加class方法
function addClass(ele, name) {
    if (name) {
        //判断该dom有没有class,有则在原class基础上增加,无则直接赋值
        ele.className ? ele.className = ele.className + " " + name : ele.className = name;
    } else {
        throw new Error("请传递一个有效的class类名");
    };
};

//自定义删除class类方法
function removeClass(ele, name) {
    //将className属性转为数组
    let classArr = ele.className.split(" "),
        index = classArr.indexOf(name);
    //将符合条件的class类删除
    index > -1 ? classArr.splice(index, 1) : null;
    ele.className = classArr.join(" ");
};

let div = document.getElementById('div1');
//测试调用
addClass(div, 'demo1');
removeClass(div, 'demo1');

四、 setAttribute方法

const divDoc = document.getElementById('div1')
let classVal = divDoc.getAttribute('class')

// 删除class1
classVal = classVal.replace('class1''')
divDoc.setAttribute('class', classVal)

// 添加class2
classVal = classVal.concat(' class1')
divDoc.setAttribute('class', classVal)

// 用class2代替class1
classVal = classVal.replace('class1''class2')
divDoc.setAttribute('class', classVal)

五、正则实现

1. 原生js实现

function hasClass(elem, cls) {
  cls = cls || ''
  if (cls.replace(/\s/g'').length === 0return false //当cls没有参数时,返回false
  return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' ')
}

function addClass(elem, cls) {
  if (!hasClass(elem, cls)) {
    elem.className = elem.className === '' ? cls : elem.className + ' ' + cls
  }
}

function removeClass(elem, cls) {
  if (hasClass(elem, cls)) {
    var newClass = ' ' + elem.className.replace(/[\t\r\n]/g'') + ' '
    while (newClass.indexOf(' ' + cls + ' ') >= 0) {
      newClass = newClass.replace(' ' + cls + ' '' ')
    }
    elem.className = newClass.replace(/^\s+|\s+$/g'')
  }
}

测试

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>引入js</title>
</head>
<body>
  <div id="div1" class="class1"></div>
</body>
<script src="add-class.js"></script>
<script>
  const divDoc = document.getElementById('div1')
  console.log('div1 has class1: 'hasClass(divDoc, 'class1'))
  console.log('div1 has class2: 'hasClass(divDoc, 'class2'))

  addClass(divDoc, 'class2')
  console.log('after addClass, div1 has class2: 'hasClass(divDoc, 'class2'))

  removeClass(divDoc, 'class1')
  console.log('after removeClass, div1 has class1: 'hasClass(divDoc, 'class1'))
</script>
</html>

运行结果结果

2. 原生JS实现jQuery的addClass, removeClass, hasClass函数功能

// obj为节点对象,eg: document.getElementById('div')
function hasClass(obj, cls) {
  var obj_class = obj.className,            //获取 class 内容.
    obj_class_lst = obj_class.split(/\s+/)   //通过split空字符将cls转换成数组.
  var x = 0
  for (x in obj_class_lst) {
    if (obj_class_lst[x] === cls) {//循环数组, 判断是否包含cls
      return true
    }
  }
  return false
}

function addClass(obj, cls) {
  var obj_class = obj.className,          //获取 class 内容.
    blank = (obj_class !== '') ? ' ' : '' //判断获取到的 class 是否为空, 如果不为空在前面加个'空格'.
  var added = obj_class + blank + cls         //组合原来的 class 和需要添加的 class.
  obj.className = added                   //替换原来的 class.
}

function removeClass(obj, cls) {
  var obj_class = ' ' + obj.className + ' '           //获取 class 内容, 并在首尾各加一个空格. ex) 'abc    bcd' -> ' abc    bcd '
  obj_class = obj_class.replace(/(\s+)/gi' ')      //将多余的空字符替换成一个空格. ex) ' abc    bcd ' -> ' abc bcd '
  var removed = obj_class.replace(' ' + cls + ' '' '//在原来的 class 替换掉首尾加了空格的 class. ex) ' abc bcd ' -> 'bcd '
  removed = removed.replace(/(^\s+)|(\s+$)/g'')     //去掉首尾空格. ex) 'bcd ' -> 'bcd'
  obj.className = removed//替换原来的 class.
}

以上就是全部总结啦,在项目中我们可以根据自己的需求酌情使用。

如果你觉得这篇文章有用,动动小手给我点个赞吧🍀