前面的话

  既然有getElementById()getElementsByTagName()方法,为什么没有getElementsByClassName()呢?id属性、标签名、class属性并没有什么优劣之分啊。终于,HTML5新增了getElementsByClassName()方法,由于在CSS布局中类名的广泛使用,该方法正好切中痛点,使得通过类名选取元素不再困难,成为最受欢迎的一个方法。接下来,本文将详细介绍该方法

使用

  HTML元素的class属性值是一个以空格隔开的列表,可以为空或包含多个标识符。在javascript中class是保留字,所以使用className属性来保存HTML的class属性值

  getElementsByClassName()方法接收一个参数,即一个包含一个或多个类名的字符串,返回带有指定类的所有元素的类数组对象HTMLCollection。传入多个类名时,类名的先后顺序不重要。与getElementsByTagName()类似,该方法既可以用于HTML文档对象,也可以用于element元素对象

  [注意]IE8-浏览器不支持

<ul id="list">
<li class="a ab c">1</li>
<li class="a">2</li>
<li class="ac">3</li>
<li class="a b c">4</li>
<li class="a b">5</li>
</ul>
<script>
//类名中存在a成立
Array.prototype.forEach.call(list.getElementsByClassName('a'),function(item,index,arr){
item.style.fontWeight = 'bold';
});
//只有类名中同时存在a和c才成立
Array.prototype.forEach.call(list.getElementsByClassName('a c'),function(item,index,arr){
item.style.color = 'red';
});
</script>

classList属性

  在操作类名时,需要通过className属性添加、删除和替换类名。因为className是一个字符串,所以即使只修改字符串一部分,也必须每次都设置整个字符串的值。要从className字符串中删除一个类名,需要把类名拆开,删除不想要的那个,再重新拼成一个新字符串

  HTML5为所有元素添加了classList属性,这个classList属性是新集合类型DOMTokenList的实例,它有一个表示自己包含多少元素的length属性,而要取得每个元素可以使用item()方法,也可以使用方括号法

  [注意]IE9-浏览器不支持

<div id="test" class="a b c"></div>
<script>
console.log(test.classList);//["a", "b", "c", value: "a b c"]
console.log(test.classList[0]);//a
console.log(test.classList.item(1));//b
</script>

  此外,这个新类型还定义如下方法:

add(value)             将给定的字符串值添加到列表中,如果值已存在,则不添加
contains(value) 表示列表中是否存在给定的值,如果存在则返回true,否则返回false
remove(value) 从列表中删除给定的字符串
toggle(value) 如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它

  有了classList属性,className属性基本没有什么用武之地了

<style>
.cB{color: blue;}
</style> <body>
<div id="test">测试文字</div>
<button id="btn1" onclick = "test.classList.add('cB')">add</button>
<button id="btn2" onclick = "test.classList.contains('cB')?alert(true):alert(false)">contains</button>
<button id="btn3" onclick = "test.classList.remove('cB')">remove</button>
<button id="btn4" onclick = "test.classList.toggle('cB')">toggle</button>
</body>

扩展

  【1】由于原生的getElementsByClassName()方法不兼容IE8-浏览器,且该方法只能完全匹配参数中的类名列表。因此有如下扩展

  扩展函数getElementsByClassName(),具有更丰富的功能。如果参数类名列表由空格分隔,则进行且匹配,即只有元素中的类名包含参数类名列表中的所有类名才算匹配成功;如果参数类名列表由逗号分隔,则进行或匹配,即只要元素中的类名包含参数类名列表中的其中一个类型就算匹配成功

Array.prototype.noRepeat = function(){
var result = [];
for(var i = 0; i < this.length; i++){
if(result.indexOf(this[i]) == -1){
result.push(this[i]);
}
}
return result;
}
Array.prototype.inArray = function(value){
for(var i = 0; i < this.length; i++){
if(this[i] === value){
return true;
}
}
return false;
}
function getElementsByClassName(parentObj,classStr){
var result = [];
//获取parentObj下的所有子元素
var objs = parentObj.getElementsByTagName('*');
//条件一:如果classStr用空格分隔,则表示class必须同时满足才有效
var targetArr1 = classStr.trim().split(/\s+/).noRepeat();
//条件二:如果classStr用逗号分隔,则表示class只要有一个满足就有效
var targetArr2 = classStr.trim().split(/\s*,\s*/).noRepeat();
//只有一个class或者进行条件一测试
if(classStr.indexOf(',') == -1 ){
label: for(var i = 0; i < objs.length; i++){
//获取每一个子元素的类名,将其转换为数组后去重
var arr = objs[i].className.trim().split(/\s+/).noRepeat();
//进入循环,测试是否符合条件一
for(var j = 0; j < targetArr1.length; j++){
//如果条件一中的某一项在arr数组中不存在,则跳过该子元素
if(!arr.inArray(targetArr1[j])){
continue label;
}
}
//将符合条件一的子元素对象放在结果数组中
result.push(objs[i]);
}
//返回结果数组
return result;
//进行条件二测试
}else{
label: for(var i = 0; i < objs.length; i++){
//获取每一个子元素的类名,将其转换为数组后去重
var arr =objs[i].className.trim().split(/\s+/).noRepeat();
//进入循环,测试是否符合条件二
for(var j = 0; j < targetArr2.length; j++){
//只要条件二的中某一项在arr数组中存在,就符合
if(arr.inArray(targetArr2[j])){
//将符合条件二的子元素对象放在结果数组中
result.push(objs[i]);
//接着进入下一个子元素测试
continue label;
}
}
}
//返回结果数组
return result;
}
}
<ul id="list">
<li class="a ab c">1</li>
<li class="a">2</li>
<li class="ac">3</li>
<li class="a b c">4</li>
<li class="a b">5</li>
</ul>
<script>
//类名中存在a成立
getElementsByClassName(list,'a').forEach(function(item,index,arr){
item.style.fontWeight = 'bold';
});
//只有类名中同时存在a和c才成立
getElementsByClassName(list,'a c').forEach(function(item,index,arr){
item.style.color = 'red';
});
//只要类名中存在b或c即成立
getElementsByClassName(list,'b,c').forEach(function(item,index,arr){
item.style.backgroundColor = 'pink';
});
</script>

  【2】由于IE9-浏览器不支持classList属性,也就不支持add()、contains()、remove()和toggle()这四个方法,下面是这四个方法的兼容写法

  由于indexOf()和trim()方法都是ES5新增方法,在低版本IE浏览器中不支持,所以需要重新封装

//数组的indexOf方法封装
function indexOf(arr,value,start){
//如果不设置start,则默认start为0
if(arguments.length == 2){
start = 0;
}
//如果数组中存在indexOf方法,则用原生的indexOf方法
if(arr.indexOf){
return arr.indexOf(value,start);
}
for(var i = start; i < arr.length; i++){
if(arr[i] === value){
return i;
}
}
return -1;
}
//数组去重方法封装
function noRepeat(arr){
var result = [];
for( var i = 0; i < arr.length; i++){
if(indexOf(result,arr[i]) == -1){
result.push(arr[i]);
}
}
return result;
}
//inArray方法封装
function inArray(arr,value){
for(var i = 0; i < arr.length; i++){
if(arr[i] === value){
return true;
}
}
return false;
}
//去除首尾空格函数封装
function trim(arr){
var result = arr.replace(/^\s+|\s+$/g,'');
return result;
}

  1、add函数封装

function addClass(obj,classStr){
var array = noRepeat(trim(obj.className).split('\s+'));
if(!inArray(array,classStr)){
array.push(classStr);
}
obj.className = array.join(' ');
return obj;
}

  2、contains函数封装

function containsClass(obj,classStr){
var array = noRepeat(trim(obj.className).split('\s+'));
if(inArray(array,classStr)){
return true;
}
return false;
}

  3、remove函数封装

function removeClass(obj,classStr){
var array = noRepeat(trim(obj.className).split('\s+'));
var index = indexOf(array,classStr);
if(index != -1){
array.splice(index,1);
obj.className = array.join(' ');
}
return obj;
}

  4、toggle函数封装

function toggleClass(obj,classStr){
var array = noRepeat(trim(obj.className).split('\s+'));
if(inArray(array,classStr)){
removeClass(obj,classStr);
}else{
addClass(obj,classStr);
}
}
<style>
.cB{color: blue;}
</style> <div id="test">测试文字</div>
<button id="btn1" onclick = "addClass(test,'cB')">add</button>
<button id="btn2" onclick = "containsClass(test,'cB')?alert(true):alert(false)">contains</button>
<button id="btn3" onclick = "removeClass(test,'cB')">remove</button>
<button id="btn4" onclick = "toggleClass(test,'cB')">toggle</button>

深入理解javascript选择器API系列第二篇——getElementsByClassName的更多相关文章

  1. 深入理解javascript选择器API系列第一篇——4种元素选择器

    × 目录 [1]id属性 [2]标签名 [3]name属性[4]all 前面的话 说到最常见的DOM应用,恐怕就要数取得特定的某个或某组元素的引用了.DOM定义了许多方式来选取元素,包括getElem ...

  2. 深入理解javascript选择器API系列第三篇——h5新增的3种selector方法

    × 目录 [1]方法 [2]非实时 [3]缺陷 前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuer ...

  3. 深入理解javascript选择器API系列第三篇——HTML5新增的3种selector方法

    前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuery的称赞,很多是由于jQuery方便的元素选择器 ...

  4. 深入理解javascript函数进阶系列第二篇——函数柯里化

    前面的话 函数柯里化currying的概念最早由俄国数学家Moses Schönfinkel发明,而后由著名的数理逻辑学家Haskell Curry将其丰富和发展,currying由此得名.本文将详细 ...

  5. 深入理解javascript函数进阶系列第一篇——高阶函数

    前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...

  6. 深入理解脚本化CSS系列第二篇——查询计算样式

    × 目录 [1]getComputedStyle [2]注意事项 [3]currentStyle[4]IE 前面的话 元素的渲染结果是多个CSS样式博弈后的最终结果,这也是CSS中的C(cascade ...

  7. 深入理解DOM事件类型系列第二篇——键盘事件

    × 目录 [1]类型 [2]顺序 [3]按键信息[4]应用 前面的话 鼠标和键盘是电脑端主要的输入设备,上篇介绍了鼠标事件,本文将详细介绍键盘事件 类型 键盘事件用来描述键盘行为,主要有keydown ...

  8. 深入理解DOM事件机制系列第二篇——事件处理程序

    × 目录 [1]HTML [2]DOM0级 [3]DOM2级[4]IE[5]总结 前面的话 事件处理程序又叫事件侦听器,实际上就是事件的绑定函数.事件发生时会执行函数中相应代码.事件处理程序有HTML ...

  9. 深入理解javascript函数系列第二篇——函数参数

    × 目录 [1]arguments [2]内部属性 [3]函数重载[4]参数传递 前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传 ...

随机推荐

  1. 烂泥:数据库管理之phpmyadmin免密码配置

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 其实这篇文章很早就想写了,但是一直没有时间.刚好今天下午稍微空了点,就把这篇文章整理出来 ...

  2. [PHP源码阅读]array_slice和array_splice函数

    array_slice和array_splice函数是用在取出数组的一段切片,array_splice还有用新的切片替换原删除切片位置的功能.类似javascript中的Array.prototype ...

  3. 一个标签的72变,打造一个纯CSS图标库

    每次要用到图标的时候都会到 icono 去copypaste,但每次用到的时候尺寸都各不一样,总是要调整参数,巨烦.当然你可以会想到用zoom.scale来做缩放,但是这样的缩放会使得线宽也变粗了,不 ...

  4. ASP.NET Web API Model-ActionBinding

    ASP.NET Web API Model-ActionBinding 前言 前面的几个篇幅把Model部分的知识点划分成一个个的模块来讲解,而在控制器执行过程中分为好多个过程,对于控制器执行过程(一 ...

  5. [译]ZooKeeper recipes-引言

    ZooKeeper高级应用 本系列将指导使用ZooKeeper来实现高级功能,所有功能都在客户端完成,不需要ZooKeeper的特殊支持.希望可以得到社区的支持将这些加入到一个标准的客户端类库中(Cu ...

  6. 通过Gradle为APK瘦身

    引言:在过去几年中,APK 文件的大小曾急剧增长态势.一般来说,其原因如下:Android开发者获取了更多的依赖库,添加了更多的密度,Apps 增加了更多的功能.但实际上我们应该让APKs 尽可能的小 ...

  7. SQL Server 批量主分区备份(Multiple Jobs)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 案例分析(Case) 方案一(Solution One) 方案二(Solution Two) ...

  8. Parallel并行之乱用

    关于Parallel我也不细说了,一则微软封装的很好用,二来介绍这个的遍地都是. 我要说的是,要想成为一个优秀的标题党,一定要把重点放到别的地方,为了节省大家阅读时间,我先把结论说了,然后再慢慢从头说 ...

  9. 开源Word读写组件DocX 的深入研究和问题总结

    一. 前言 前两天看到了asxinyu大神的[原创]开源Word读写组件DocX介绍与入门,正好我也有类似的自动生成word文档得需求,于是便仔细的研究了这个DocX. 我也把它融入到我的项目当中并进 ...

  10. 当master down掉后,pt-heartbeat不断重试会导致内存缓慢增长

    最近同事反映,在使用pt-heartbeat监控主从复制延迟的过程中,如果master down掉了,则pt-heartbeat则会连接失败,但会不断重试. 重试本无可厚非,毕竟从使用者的角度来说,希 ...