深入理解javascript选择器API系列第二篇——getElementsByClassName
前面的话
既然有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为0if(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相关推荐
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
- 深入理解脚本化CSS系列第二篇——查询计算样式
前面的话 元素的渲染结果是多个CSS样式博弈后的最终结果,这也是CSS中的C(cascade)层叠的含义.访问第一篇中的style属性只能获取行间样式,这通常来说,并不是我们想要的结果.本文将详细介绍 ...
- 深入理解javascript函数系列第二篇——函数参数
前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...
- 前端工程师技能之photoshop巧用系列第二篇——测量篇
前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇--测量篇 测量信息 在网页制作中需要使用photoshop测量的信息分为两类,分别是尺寸信息和颜色信 ...
- 焱老师带你学习MYSQL系列 第二篇 (MYSQL 数据结构)
相关系列链接 焱老师带你学习MYSQL系列 第六篇 (MYSQL是如何实现锁的) 焱老师带你学习MYSQL系列 第五篇 (MYSQL事务隔离级别是如何实现的) 焱老师带你学习MYSQL系列 第四篇 ( ...
- 深入理解表单脚本系列第一篇——表单对象
前面的话 javascript最初的一个应用就是分担服务器处理表单的责任,打破处处依赖服务器的局面.尽管目前的web和javascript已经有了长足的发展,但web表单的变化并不明显.由于web表单 ...
- 阿里出品移动研发“神器” 阿里移动云系列第二篇|“移”步到位:一站式移动应用研发体系...
摘要:2017杭州云栖大会阿里移动云峰会专场上,阿里巴巴高级技术专家小木带来一站式应用研发体系方面的演讲.本文主要以互联网的应用背景开始谈起,进而阐述了已拥有APP的企业在APP的生命周期中会遇见哪些 ...
- [游戏开发]Python打表工具系列 [第二篇] [打表流程描简述]
[上一篇链接] [游戏开发]Python打表工具系列 [第一篇][IDE开发环境部署] VSCode Python环境调试_Little丶Seven的博客-CSDN博客 [前言] 第二篇文章是对流程的 ...
- 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame
前面的话 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好处呢?为什么requestAnimationFrame被称为神器呢 ...
最新文章
- python算法和数据结构_Python中的数据结构和算法
- 续--Flask, Django - 区别
- selenium使用TestNG实现DDT
- linux: kill -9
- SAP License:BWBCS学习笔记
- ffmpeg下载rtmp flv
- java计算机毕业设计教务排课系统MyBatis+系统+LW文档+源码+调试部署
- 在matlab中输出怎么表示什么意思,matlab中基于帧输出是什么意思
- AGV项目底层总结二
- 摔手机问题--第九届蓝桥杯
- 启动IDEA都会打开Licenses激活弹窗
- 易企秀 we+ Maka 兔展 四大H5页面制作工具
- CRC碰撞概率 与CRC校验长度的理解
- 使用telnet来在线调试海思开发板
- 珍贵!分享!全国各省市最全乡镇、街道行政区划边界shp矢量数据+wgs84坐标系+2021年7月最新获取+2018年更新数据
- 2021年四川省大学生信息安全技术大赛部分WP (四川省赛WP)
- Qt + 觸控 移植 – Qt and Touch Screen Porting to SBC6446 with LEOs for DaVinci
- 错误集:smbclient访问Windows共享文件夹报错误:protocol negotiation failed: NT_STATUS_CONNECTION_RESET
- 微信小程序下拉刷新真机没效果_微信小程序 下拉刷新 上拉加载(示例代码)
- 【git】Your configuration specifies to merge with the ref ‘refs/heads/xxx