document.getElementsByClassName的理想实现
来源:互联网 发布:揭阳华诺网络 编辑:程序博客网 时间:2024/05/06 11:18
document.getElementsByClassName的理想实现
各种实现方式
Pure DOM
通常先使用getElementsByTagName("*")取出文档中所有元素,然后进行遍历,使用正则表达式找出匹配的元素放入一个数组返回。由于IE5不支持document.getElementsByTagName("*"),要使用分支document.all以防错误。
The Ultimate getElementsByClassName方案,作者为Robert Nyman,05年实现,可见老外许多东西在很早以前就走得很远了。
//三个参数都是必需的,查找一网页中5007个类名为“cell”的元素,IE8历时1828 ~ 1844毫秒,
//IE6为4610 ~ 6109毫秒,FF3.5为46 ~ 48毫秒,opera10为31 ~ 32毫秒,Chrome为23~ 26毫秒,
//safari4为19 ~ 20毫秒
function
getElementsByClassName(oElm, strTagName, strClassName){
var
arrElements = (strTagName ==
"*"
&& oElm.all)? oElm.all :
oElm.getElementsByTagName(strTagName);
var
arrReturnElements =
new
Array();
strClassName = strClassName.replace(/\-/g,
"\\-"
);
var
oRegExp =
new
RegExp(
"(^|\\s)"
+ strClassName +
"(\\s|$)"
);
var
oElement;
for
(
var
i=0; i < arrElements.length; i++){
oElement = arrElements[i];
if
(oRegExp.test(oElement.className)){
arrReturnElements.push(oElement);
}
}
return
(arrReturnElements)
}
另一个实现,由Dustin Diaz(《JavaScript Design Patterns》的作者)提供,但兼容性不如上面的,不支持IE5。
//后两参数是可靠的,查找一网页中5007个类名为“cell”的元素,IE8历时78毫秒,IE6历时125~171毫秒
//FF3.5为42 ~ 48毫秒,opera10为31 毫秒,Chrome为22~ 25毫秒,safari4为18 ~ 19毫秒
var
getElementsByClass =
function
(searchClass,node,tag) {
var
classElements =
new
Array();
if
( node ==
null
)
node = document;
if
( tag ==
null
)
tag =
'*'
;
var
els = node.getElementsByTagName(tag);
var
elsLen = els.length;
var
pattern =
new
RegExp(
"(^|\\s)"
+searchClass+
"(\\s|$)"
);
for
(i = 0, j = 0; i < elsLen; i++) {
if
( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return
classElements;
}
还有个更古老级的,我从prototype.js1.01版本中找到的,它能支持多个类名的查找(上面两个不行)。它不支持IE5,效率一般般,但作为最早的框架之一,它已经做得很好,其他框架还没有想到这个呢!
//由于这是后期添加的,测试页面已被我删掉,没有做测试……
function
getElementsByClassName(className, element) {
var
children = (element || document).getElementsByTagName(
'*'
);
var
elements =
new
Array();
for
(
var
i = 0; i < children.length; i++) {
var
child = children[i];
var
classNames = child.className.split(
' '
);
for
(
var
j = 0; j < classNames.length; j++) {
if
(classNames[j] == className) {
elements.push(child);
break
;
}
}
}
return
elements;
}
DOM Tree Walker
使用document.createTreeWalker,这是个比较不常用的二级DOM方法。可惜IE全系列歇菜。
//查找一网页中5007个类名为“cell”的元素,FF3.5为104 ~ 119毫秒,opera10为230 ~ 265毫秒,
//Chrome为119 ~ 128毫秒,safari为28 ~ 32毫秒
var
getElementsByClassName =
function
(searchClass) {
function
acceptNode(node) {
if
(node.hasAttribute(
"class"
)) {
var
c =
" "
+ node.className +
" "
;
if
(c.indexOf(
" "
+ searchClass +
" "
) != -1)
return
NodeFilter.FILTER_ACCEPT;
}
return
NodeFilter.FILTER_SKIP;
}
var
treeWalker = document.createTreeWalker(document.documentElement,
NodeFilter.SHOW_ELEMENT, acceptNode,
true
);
var
returnElements = [];
if
(treeWalker) {
var
node = treeWalker.nextNode();
while
(node) {
returnElements.push(node);
node = treeWalker.nextNode();
}
}
return
returnElements;
}
XPath
更加新式时髦的技术。
下面取自Prototype.js框架。
document.getElementsByClassName =
function
(className, parentElement) {
if
(Prototype.BrowserFeatures.XPath) {
var
q =
".//*[contains(concat(' ', @class, ' '), ' "
+ className +
" ')]"
;
return
document._getElementsByXPath(q, parentElement);
}
else
{
var
children = ($(parentElement) || document.body).getElementsByTagName(
'*'
);
var
elements = [], child;
for
(
var
i = 0, length = children.length; i < length; i++) {
child = children[i];
if
(Element.hasClassName(child, className))
elements.push(Element.extend(child));
}
return
elements;
}
};
由于这个是不能运行的,我们修改如下:
//查找一网页中5007个类名为“cell”的元素,FF3.5为33 ~ 48毫秒,opera10为31 ~ 32毫秒,
//Chrome为104 ~ 107毫秒,safari为18 ~ 21毫秒
var
getElementsByClassName =
function
(searchClass,node,tag) {
node = node || document;
tag = tag ||
'*'
;
var
classes = searchClass.split(
" "
),
patterns =
""
,
xhtmlNamespace =
"http://www.w3.org/1999/xhtml"
,
namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace :
null
,
returnElements = [],
elements,
_node;
for
(
var
j=0, jl=classes.length; j<jl; j+=1){
patterns +=
"[contains(concat(' ', @class, ' '), ' "
+ classes[j] +
" ')]"
;
}
try
{
elements = document.evaluate(
".//"
+ tag + patterns, node, namespaceResolver, 0,
null
);
}
catch
(e) {
elements = document.evaluate(
".//"
+ tag + patterns, node,
null
, 0,
null
);
}
while
((_node = elements.iterateNext())) returnElements.push(_node);
return
returnElements;
}
当然如果游览器原生支持,就用原生的。
速度比较一览
综合以上方案,我得出了一个最理想的实现——兼容IE5,让后面两个参数是可选的,能原生的原生,利用字面量与倒序循环提高效率……
//查找一网页中5007个类名为“cell”的元素,IE8历时1828 ~ 1844毫秒,
//IE6为125 ~ 172毫秒,IE8为93 ~ 94毫秒,FF3.5为0~1毫秒,opera10为0毫秒,Chrome为1毫秒,
//safari4为0毫秒
var
getElementsByClassName =
function
(searchClass,node,tag) {
if
(document.getElementsByClassName){
return
document.getElementsByClassName(searchClass)
}
else
{
node = node || document;
tag = tag ||
'*'
;
var
returnElements = []
var
els = (tag ===
"*"
&& node.all)? node.all : node.getElementsByTagName(tag);
var
i = els.length;
searchClass = searchClass.replace(/\-/g,
"\\-"
);
var
pattern =
new
RegExp(
"(^|\\s)"
+searchClass+
"(\\s|$)"
);
while
(--i >= 0){
if
(pattern.test(els[i].className) ) {
returnElements.push(els[i]);
}
}
return
returnElements;
}
}
用法:
var
collections = getElementsByClassName(
"red"
);
但它还是不如原生的getElementsByClassName,不能同时检索多个class
<h2 class="red cell title">安装支持</h2><span class="cell red ">jjj</span><div class="filament_table red cell">这是DIV</div>#利用 var dd = getElementsByClassName("cell red") ,这三个元素都应该能被检索到!
因此,最最终的方案为:
var getElementsByClassName = function (searchClass, node,tag) { if(document.getElementsByClassName){ var nodes = (node || document).getElementsByClassName(searchClass),result = []; for(var i=0 ;node = nodes[i++];){ if(tag !== "*" && node.tagName === tag.toUpperCase()){ result.push(node) } } return result }else{ node = node || document; tag = tag || "*"; var classes = searchClass.split(" "), elements = (tag === "*" && node.all)? node.all : node.getElementsByTagName(tag), patterns = [], current, match; var i = classes.length; while(--i >= 0){ patterns.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)")); } var j = elements.length; while(--j >= 0){ current = elements[j]; match = false; for(var k=0, kl=patterns.length; k<kl; k++){ match = patterns[k].test(current.className); if (!match) break; } if (match) result.push(current); } return result; } }
0 0
- document.getElementsByClassName的理想实现
- document.getElementsByClassName的理想实现
- document.getElementsByClassName 的理想实现
- document.getElementsByClassName的理想实现
- [转]document.getElementsByClassName的理想实现]
- 【转】document.getElementsByClassName的理想实现
- document.getElementsByClassName 的兼容性写法
- 我的getElementsByClassName实现
- 解决 IE 不支持 document.getElementsByClassName() 的方法
- document.getElementsByClassName的封装,兼容ie8
- document.getElementsByClassName For IE
- document.getElementsByClassName 兼容性
- document.getElementsByClassName兼容性问题
- document.getElementsByClassName在ie8及其以下浏览器的兼容性问题
- document.getElementsByClassName在ie8及其以下浏览器的兼容性问题
- document.getElementById(), getElementsByname(),getElementsByClassName(),getElementsByTagName()
- 解决 IE 不支持 document.getElementsByClassName()
- IE8重写document.getElementsByClassName方法
- 面试失败:求职成功的一把“金钥匙”
- 关于mysqljdbc连接驱动的两种不同方式
- ActiveMQ中使用mysql做持久化报错:Cannot execute statement: impossible to write to binary log since BINLOG_FORM
- ubuntu 创建svn
- Arduino读取加速度传感器MC3210
- document.getElementsByClassName的理想实现
- 发布 Asp.net 应用 提示 500 错误,解决办法。
- 优秀博文连接
- C指针原理(41)-c++-boost(日期时间)
- Deep Learning(深度学习) 学习笔记(一)
- ORACLE分区表的使用和管理
- 开始学习芯片出的些错误
- Racket中的define、let和let*
- ToString()用法