转载:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1529640.html?login=1#commentform
通常先使用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; |
} |
使用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; |
} |
更加新式时髦的技术。
下面取自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; |
} |
当然如果游览器原生支持,就用原生的。
各主流游览器的支持情况 | ||||||||
---|---|---|---|---|---|---|---|---|
IE8 | IE7 | IE6 | FF3 | FF2 | Saf3 | Op9 | Op10 | Chrome |
N | N | N | Y | N | Y | Y | Y | Y |
综合以上方案,我得出了一个最理想的实现——兼容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) |
}else{ |
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; |
} |
} |
顶一下。不知LZ研究过jQuery获取元素的方法没有,甚是强大! 回复 引用 查看
你这个函数是错误的,
if(document.getElementsByClassName){
return document.getElementsByClassName(searchClass)
}
问:标准里没有fatherDom.getElementsByClassName("childTag",classNames)
回复 引用 查看
@笨蛋的座右铭
没有
getElementsByClassName只有一个参数
不过调用者可以是document或元素节点 回复 引用 查看
你这个函数确实是不正确的,看如下代码在IE和opera下运行结果:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
<html xmlns="http://www.w3.org/1999/xhtml"> |
<head> |
<title>getElementByClass</title> |
</head> |
<body> |
<script type="text/javascript"> |
var getElementsByClassName = function (searchClass, node,tag) { |
if(document.getElementsByClassName){ |
return document.getElementsByClassName(searchClass) |
}else{ |
node = node || document; |
tag = tag || "*"; |
var classes = searchClass.split(" "), |
elements = (tag === "*" && node.all)? node.all : node.getElementsByTagName(tag), |
patterns = [], |
returnElements = [], |
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) returnElements.push(current); |
} |
return returnElements; |
} |
} |
window.onload = function(){ |
var father = document.getElementById("father"); |
alert(getElementsByClassName("aaa bbb",father,"span").length); |
} |
</script> |
<div id="father"> |
<span class="aaa bbb ccc"><span> |
<span class="aaa bbb zzz"></span> |
</div> |
<span class="aaa bbb ccc"><span> |
<span class="aaa bbb zzz"></span> |
</body> |
</html> |
//扩展getElementsByClassName
function getElementsByClassName(searchClass, node,tag) {
if(document.getElementsByClassName){
var nodes = (node || document).getElementsByClassName(searchClass),result = nodes;
if(tag!=undefined){
result = [];
for(var i=0 ;node = nodes[i++];){
if(tag !== "*" && node.tagName === tag.toUpperCase()){
result.push(node);
}else{
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 = [],
returnElements = [],
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) returnElements.push(current);
}
return returnElements;
}
};