对于js来说,我想每一个刚接触它的人都应该会抱怨:为什么没有一个通过class来获取元素的方法。尽管现在高版本的浏览器已经支持getElementsByClassName()函数,但是对于低版本浏览器来说,还是无法兼容,在脱离其他库的时候,还是得自己封装一个方法。
方法一
1
2
3
4
5
6
7
8
9
10
|
function getByClass1(parent,
cls
){
var res
=
[];
/
/
存放匹配结果的数组
var ele
=
parent.getElementsByTagName(
'*'
);
for
(var i
=
0
; i < ele.length; i
+
+
){
if
(ele[i].className
=
=
cls
){
res.push(ele[i]);
}
}
return
res;
}
|
当然class里的值只有一个时,上面的方法没问题,但当值为多个时,就会出现问题。
1
2
3
4
5
|
<div class=
"test"
></div>
<div class=
"test box"
></div>
<script>
getByClass1(document,
'test'
);
//只获取到第一个div
</script>
|
方法二
出现问题的时候,我们会尝试着改进,对于多类名的情况我们可以用正则去匹配是否包含所要查找的class名,于是就出现了下面这种写法:
1
2
3
4
5
6
7
8
9
10
11
|
function
getByClass2(parent, cls){
var
res = [];
var
reg =
new
RegExp(
'\\b'
+ cls +
'\\b'
,
'i'
);
//匹配cls是一个独立的单词
var
ele = parent.getElementsByTagName(
'*'
);
for
(
var
i = 0; i < ele.length; i++){
if
(reg.test(ele[i].className)){
res.push(ele[i]);
}
}
return
res;
}
|
这种方法看似可以,解决了getByClass1()的问题,我也用了好长一段时间,但是还会有一个隐藏的bug。看下面的例子:
1
2
3
4
5
6
|
<div class=
"test"
></div>
<div class=
"test_box"
></div>
<div class=
"test-box"
></div>
<script>
getByClass2(document,
'test'
);
//结果获取到了第一个div和第三个div
</script>
|
理论上应该只获取到第一个,但是却和我们预期不一样。这个bug源于下面这段代码里的\b
1
|
var
reg =
new
RegExp(
'\\b'
+ cls +
'\\b'
,
'i'
);
|
我们先来看下\b在正则中的表示的意思
\b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,也就是单词的分界处。
通俗点说:\b就是匹配一个单词(从左边界到右边界)。
而问题也就出在这里,\b把除字母、数字、下划线外的其他字符都当成是边界,对于上面的例子中第三个class值为test-box,\b匹配时,把连字符(-)当作单词边界,所以也匹配了第三个div。
方法三
因此我们还需要对上面方法进行进一步改进,这里参考了stackoverflow上提到的一种方法:
How to Get Element By Class in JavaScript?
改进后的代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
function
getByClass3(parent, cls){
var
res = [];
var
reg =
new
RegExp(
' '
+ cls +
' '
,
'i'
);
//匹配cls时,两边需要有空格
var
ele = parent.getElementsByTagName(
'*'
);
for
(
var
i = 0; i < ele.length; i++){
if
(reg.test(
' '
+ ele[i].className +
' '
)){
res.push(ele[i]);
}
}
return
res;
}
|
这种方法舍去了用\b而采用空格来匹配边界,先在获取到的className值两边加上空格,这样就保证了className里的每个值两边都会有空格,然后再用正则去匹配。
用这种方法暂时还未发现问题,但是使用时,方法中的单引号内的空格一定不能落下。
方法四
1
2
3
4
5
6
7
8
9
10
11
|
function
getByClass3(parent, cls){
var
res = [];
var
reg =
new
RegExp(
'(^|\\s)'
+ cls +
'($|\\s)'
,
'i'
);
var
ele = parent.getElementsByTagName(
'*'
);
for
(
var
i = 0; i < ele.length; i++){
if
(reg.test(ele[i].className)){
res.push(ele[i]);
}
}
return
res;
}
|
空格完全用正则来处理,这样省去了空格容易落下的问题,代码也更美观精简。
那么这种方法是否就是比较完美的呢,其实不然,下面来看下更优的方案。
方法五(完美版)
文章开头已经提到,高版本的浏览器已经支持getElementsByClassName()方法。出于性能考虑,对支持的浏览器使用原生方法势必会更好。而对于低版本的浏览器使用上面的方法四。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function
getByClass(parent, cls){
if
(parent.getElementsByClassName){
return
parent.getElementsByClassName(cls);
}
else
{
var
res = [];
var
reg =
new
RegExp(
' '
+ cls +
' '
,
'i'
)
var
ele = parent.getElementsByTagName(
'*'
);
for
(
var
i = 0; i < ele.length; i++){
if
(reg.test(
' '
+ ele[i].className +
' '
)){
res.push(ele[i]);
}
}
return
res;
}
}
对于js来说,我想每一个刚接触它的人都应该会抱怨:为什么没有一个通过class来获取元素的方法。尽管现在高版本的浏览器已经支持getElementsByClassName()函数,但是对于低版本浏览器来说,还是无法兼容,在脱离其他库的时候,还是得自己封装一个方法。 方法一
当然class里的值只有一个时,上面的方法没问题,但当值为多个时,就会出现问题。
方法二 出现问题的时候,我们会尝试着改进,对于多类名的情况我们可以用正则去匹配是否包含所要查找的class名,于是就出现了下面这种写法:
这种方法看似可以,解决了getByClass1()的问题,我也用了好长一段时间,但是还会有一个隐藏的bug。看下面的例子:
理论上应该只获取到第一个,但是却和我们预期不一样。这个bug源于下面这段代码里的\b
我们先来看下\b在正则中的表示的意思 \b是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,也就是单词的分界处。 通俗点说:\b就是匹配一个单词(从左边界到右边界)。 而问题也就出在这里,\b把除字母、数字、下划线外的其他字符都当成是边界,对于上面的例子中第三个class值为test-box,\b匹配时,把连字符(-)当作单词边界,所以也匹配了第三个div。 方法三 因此我们还需要对上面方法进行进一步改进,这里参考了stackoverflow上提到的一种方法: How to Get Element By Class in JavaScript? 改进后的代码如下:
这种方法舍去了用\b而采用空格来匹配边界,先在获取到的className值两边加上空格,这样就保证了className里的每个值两边都会有空格,然后再用正则去匹配。 用这种方法暂时还未发现问题,但是使用时,方法中的单引号内的空格一定不能落下。 方法四
空格完全用正则来处理,这样省去了空格容易落下的问题,代码也更美观精简。 那么这种方法是否就是比较完美的呢,其实不然,下面来看下更优的方案。 方法五(完美版) 文章开头已经提到,高版本的浏览器已经支持getElementsByClassName()方法。出于性能考虑,对支持的浏览器使用原生方法势必会更好。而对于低版本的浏览器使用上面的方法四。
|