js中getByClass()函数进化史

对于js来说,我想每一个刚接触它的人都应该会抱怨:为什么没有一个通过class来获取元素的方法。尽管现在高版本的浏览器已经支持getElementsByClassName()方法,但是对于低版本浏览器来说,还是无法兼容,在脱离其他库的时候,还是得自己封装一个方法。

下面列举几种网上常见的方法并说明存在的一些问题。

 

方法一

function getByClass(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里的值只有一个时,上面的方法没问题,但当值为多个时,就会出现问题。

<div class="test"></div>
<div class="test box"></div>
<script>
    getByClass(document, 'test');  //只获取到第一个div
</script>

 

方法二

对于多类名的情况我们可以用正则去匹配是否包含所要查找的class名,于是就出现了下面这种写法:

function getByClass(oParent, sClass){
    var aRes = [];
    var re = new RegExp('\\b' + sClass + '\\b', '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;
}

这种方法解决了方法一的问题,但是还会有一个隐藏的bug:

<div class="test"></div>
<div class="test_box"></div>
<div class="test-box"></div>
<script>
    getByClass(document, 'test');  //结果获取到了第一个div和第三个div
</script>

理论上应该只获取到第一个,但是却和我们预期不一样。这个bug源于下面这段代码里的\b

var re = new RegExp('\\b' + sClass + '\\b', 'i');

我们先来看下\b在正则中的表示的意思

 \b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,也就是单词的分界处。

通俗点说:\b就是匹配一个单词(从左边界到右边界)。

而问题也就出在这里,\b把除字母、数字、下划线外的其他字符都当成是边界,对于上面的例子中第三个class值为test-box,\b匹配时,把连字符(-)当作单词边界,所以也匹配了第三个div。

 

方法三

function getByClass(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里的每个值两边都会有空格,然后再用正则去匹配。

用这种方法暂时还未发现问题,但是使用时,方法中的单引号内的空格一定不能落下。

 

方法四

根据@冰麟轻武 的提示继续改进:

function getByClass(oParent, sClass){
    var aRes = [];
    var re = new RegExp('(^|\\s)' + sClass + '($|\\s)', 'i');
    var aEle = oParent.getElementsByTagName('*');
    for(var i = 0; i < aEle.length; i++){
        if(re.test(aEle[i].className)){
            aRes.push(aEle[i]);
        }
    }
    return aRes;
}

空格完全用正则来处理,这样省去了空格容易落下的问题,代码也更美观精简。

那么这种方法是否就是比较完美的呢,其实不然,下面来看下更优的方案。

 

方法五(完美版)

文章开头已经提到,高版本的浏览器已经支持getElementsByClassName()方法。出于性能考虑,对支持的浏览器使用原生方法势必会更好。而对于低版本的浏览器使用上面的方法四。

function getByClass(oParent, sClass){
    if(oParent.getElementsByClassName){
        return oParent.getElementsByClassName(sClass);
    }else{
        var aRes = [];
        var re = new RegExp('(^|\\s)' + sClass + '($|\\s)', 'i');
        var aEle = oParent.getElementsByTagName('*');
        for(var i = 0; i < aEle.length; i++){
            if(re.test(aEle[i].className)){
                aRes.push(aEle[i]);
            }
        }
        return aRes;
    }
}

 

转自 http://www.cnblogs.com/webmoon/

转载于:https://www.cnblogs.com/8ways/articles/4296645.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值