getByClass()函数进化史
2015-09-18 22:26
169 查看
对于js来说,我想每一个刚接触它的人都应该会抱怨:为什么没有一个通过class来获取元素的方法。尽管现在高版本的浏览器已经支持getElementsByClassName()方法,但是对于低版本浏览器来说,还是无法兼容,在脱离其他库的时候,还是得自己封装一个方法。
当然class里的值只有一个时,上面的方法没有问题,但当值为多个时,就会出现问题。
这种方法看似可以,解决了getByClass1()的问题,我也用了好长一段时间,但是还会有一个隐藏的bug。看下面的例子:
理论上应该只获取到第一个,但是却和我们预期不一样。这个bug源于下面这段代码里的/b
var re = new RegExp('//b' + sClass + '//b');
我们先来看下/b在正则中的表示的意思:/b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,也就是单词的分界处。通俗点说:/b就是匹配一个单词(从左边界到右边界)。而问题也就出在这里,/b把除字母、数字、下划线外的其他字符都当成是边界,对于上面的例子中第三个class值为test-box,/b匹配时,把连字符(-)当作单词边界,所以也匹配了第三个div。
因此我们还需要对上面方法进行进一步改进,这里参考了stackoverflow上提到的一种方法:How to Get Element By Class in JavaScript?
改进后的代码如下:
这种方法舍去了用/b而采用空格来匹配边界,先在获取到的className值两边加上空格,这样就保证了className里的每个值两边都会有空格,然后再用正则去匹配。用这种方法暂时还未发现问题,但是使用时,方法中的单引号内的空格一定不能落下。那么这种方法是否就是比较完美的呢,其实不然,下面来看下更优的方案。
文章开头已经提到,高版本的浏览器已经支持getElementsByClassName()方法。出于性能考虑,对支持的浏览器使用原生方法势必会更好。而对于低版本的浏览器使用上面的方法三。
当然方法四自认为是相对较好的方案,如果有更优秀的方法欢迎留言补充。
方法一:
function getByClass1(oParent, sClass){ var aRes = []; //存放匹配结果的数组 var aEle = oParent.getElementsByTagName('*'); for(var i = 0; i < aEle.length; i++){ if(aEle[i].className == sClass){ aRes.push(aEle[i]); } } return aRes; }
当然class里的值只有一个时,上面的方法没有问题,但当值为多个时,就会出现问题。
方法二:
出现问题的时候,我们尝试着改进,对于多类名的情况我们可以用正则去匹配是否包含所要查找的class名,于是就出现了下面这种写法:function getByClass2(oParent, sClass){ var aRes = []; var re = new RegExp('//b' + sClass + '//b'); //匹配sClass是一个独立的单词 var aEle = oParent.getElementsByTagName('*'); for(var i = 0; i < aEle.length; i++){ if(re.test(aEle[i].className)){ aRes.push(aEle[i]); } } return aRes; }
这种方法看似可以,解决了getByClass1()的问题,我也用了好长一段时间,但是还会有一个隐藏的bug。看下面的例子:
<div class="test"></div> <div class="test_box"></div> <div class="test-box"></div> //通过tese获取到了第一个div和第三个div
理论上应该只获取到第一个,但是却和我们预期不一样。这个bug源于下面这段代码里的/b
var re = new RegExp('//b' + sClass + '//b');
我们先来看下/b在正则中的表示的意思:/b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,也就是单词的分界处。通俗点说:/b就是匹配一个单词(从左边界到右边界)。而问题也就出在这里,/b把除字母、数字、下划线外的其他字符都当成是边界,对于上面的例子中第三个class值为test-box,/b匹配时,把连字符(-)当作单词边界,所以也匹配了第三个div。
方法三:
因此我们还需要对上面方法进行进一步改进,这里参考了stackoverflow上提到的一种方法:How to Get Element By Class in JavaScript?改进后的代码如下:
function getByClass3(oParent, sClass){ var aRes = []; var re = new RegExp(' ' + sClass + ' ', 'i'); //匹配sClass时,两边需要有空格 var aEle = oParent.getElementsByTagName('*'); for(var i = 0; i < aEle.length; i++){ if(re.test(' ' + aEle[i].className + ' ')){ aRes.push(aEle[i]); } } return aRes; }
这种方法舍去了用/b而采用空格来匹配边界,先在获取到的className值两边加上空格,这样就保证了className里的每个值两边都会有空格,然后再用正则去匹配。用这种方法暂时还未发现问题,但是使用时,方法中的单引号内的空格一定不能落下。那么这种方法是否就是比较完美的呢,其实不然,下面来看下更优的方案。
方法四(完美版):
文章开头已经提到,高版本的浏览器已经支持getElementsByClassName()方法。出于性能考虑,对支持的浏览器使用原生方法势必会更好。而对于低版本的浏览器使用上面的方法三。function getByClass(oParent, sClass){ if(oParent.getElementsByClassName){ return oParent.getElementsByClassName(sClass); }else{ var res = []; var re = new RegExp(' ' + sClass + ' ', 'i') var aEle = oParent.getElementsByTagName('*'); for(var i = 0; i < aEle.length; i++){ if(re.test(' ' + aEle[i].className + ' ')){ res.push(aEle[i]); } } return res; } }
当然方法四自认为是相对较好的方案,如果有更优秀的方法欢迎留言补充。
相关文章推荐
- 开发常用工具
- 程序的异常处理(C#)
- 例题 6-12 油田 UVa 572 用dfs求连通块
- 黑马程序员--------构造方法
- Android在代码中调用XML中设置的自定义View属性
- iOS UI基础-9.2 UITableView 简单微博列表
- 第三周 项目3-求集合并集
- 结构的嵌套
- SYN DDOS 防御策略
- 滑动窗口与拥塞窗口
- mysql
- android自动化测试——monkey(2)
- Spring管理 hibernate 事务配置的五种方式
- 关于垃圾回收(GC和Marshal)有感
- 大道至简读后感
- ZOJ 1610 Count the Colors (线段树区间染色)
- 计算机中树的优点与重要性
- 几个VS编译器(cl.exe)命令行编译的例子
- CentOS中由一般用户切换为root用户
- c++实现八大排序方法(一)