前面的话

  既然有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. 在Ubuntu下安装ovs-dpdk

    在Ubuntu下安装ovs-dpdk 参考资料:https://software.intel.com/zh-cn/articles/using-open-vswitch-with-dpdk-on-ub ...

  2. mono3.2和monodevelop4.0在ubuntu12.04上两天的苦战

    首先第一步是设置ubuntu server 12.04版更新源,推荐中科大的比较快:deb http://debian.ustc.edu.cn/ubuntu/ precise main multive ...

  3. Xamarin.Android-用ZXing实现二维码扫描以及连续扫描

    一.前言 本文的内容有两个基础:ZXing.Net和ZXing.Net.Mobile ZXing.Net:ZXing的C#实现,主要封装了各种二维码的编码.解码等跨平台的算法 ZXing.Net.Mo ...

  4. 使用Hystrix提高系统可用性

    今天稍微复杂点的互联网应用,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系,依赖都是通过网络连接起来. (图片来源:https://github.com/Netfli ...

  5. Lesson 17 Always young

    Text My aunt Jennifer is an actress. She must be at least thirty-five years old. In spit of this, sh ...

  6. Go语言实战

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文通过从无到有创建一个利用Go语言实现的非常简单的HttpServe ...

  7. 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序

    在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...

  8. Android-环境问题

    大家都知道 Android Studio 是 Goole 的亲儿子,但,亲儿子毕竟也是刚出生2年不到,身上大毛病没有,小毛病大一堆,这篇博文就来总结一下常见的Android Studio 的设置,使用 ...

  9. CI Weekly #5 | 微服务架构下的持续部署与交付

    CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...

  10. IOC的理解

    转载http://www.cnblogs.com/xdp-gacl/p/4249939.html 很不错的文章,虽说是java的,但是.net也通用,所以复制一分,拿来看看挺不错的. 1.1.IoC是 ...