前面的话

  既然有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. 数据库 DML、DDL、DCL区别 .

    总体解释: DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的 ...

  2. Autofac 的点滴

    泛型类型的注册和使用 public interface IRepository<T> where T:class { } public interface ISchoolDetailRep ...

  3. Storm构建分布式实时处理应用初探

    最近利用闲暇时间,又重新研读了一下Storm.认真对比了一下Hadoop,前者更擅长的是,实时流式数据处理,后者更擅长的是基于HDFS,通过MapReduce方式的离线数据分析计算.对于Hadoop, ...

  4. 高性能Javascript--高效的数据访问

    接上一篇,希望能写一个高性能Javascript专题. 第一篇:高性能Javascript--脚本的无阻塞加载策略. 参考摘录<高性能Javascript>. 经典计算机科学的一个问题是, ...

  5. .Net 4.5可执行程序OutOfMemory

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com   产线上新部署的服务,发生几次无故停止的情况,通过系统事件看到是这样:   这个服务缓存了大量的数据,内存占用比 ...

  6. Windows Server 2008 小操作汇总

    用惯了Windows2003,去配置2008的时候还真有点摸不着头脑.干脆把有用到的都列在这里,方便后续查找. 一.安装IIS.Telnet      点击:开始 -> 管理工具 -> 服 ...

  7. [翻译]AKKA笔记 - ACTOR生命周期 - 基本 -5

    原文地址:http://rerun.me/2014/10/21/akka-notes-actor-lifecycle-basic/ (请注意这了讨论的生命周期并不包括 preRestart 或者pos ...

  8. java运行时获得泛型类型

    引言 众所周知,java泛型最重要的特征是泛型擦除,所有泛型在编译时会转换成Object所以在java中运行时无法获得泛型的类型. 但是其实以上的规则是针对方法的内部变量的,如果是其他形式的泛型其实是 ...

  9. VR ( Virtual Reality )、AR(Augmented Reality)、MR(Mix Reality)和CR(Cinematic Reality)是什么鬼?

    整个社会对虚拟现实的研究和开发源于上个世纪六十年代,计算机图形学.人机接口技术.图像处理与模式识别.多传感技术.语音处理与音响技术.高性能计算机系统.人工智能等领域在之后半个世纪取得了长足的发展为虚拟 ...

  10. Java中isAssignableFrom的用法

    class1.isAssignableFrom(class2) 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口.如果是则返回 tru ...