首先我们看jquery作者的一篇getElementsByClassName Speed Comparison
有三种实现
1 纯DOM:通过getElementsByClassName("*")来遍历所有的dom元素,然后用正则判断className
2 DOM TreeWalker:dom2实现
3 XPath:通过XPath引擎来实现遍历
dom TreeWalker。通过使用dom level 2实现。
document.getElementsByClass
=
function
(needle) {
function acceptNode(node) {
if (node.hasAttribute( " class " )) {
var c = " " + node.className + " " ;
if (c.indexOf( " " + needle + " " ) != - 1 )
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}
var treeWalker = document.createTreeWalker(document.documentElement,
NodeFilter.SHOW_ELEMENT, acceptNode, true );
var outArray = new Array();
if (treeWalker) {
var node = treeWalker.nextNode();
while (node) {
outArray.push(node);
node = treeWalker.nextNode();
}
}
return outArray;
}
function acceptNode(node) {
if (node.hasAttribute( " class " )) {
var c = " " + node.className + " " ;
if (c.indexOf( " " + needle + " " ) != - 1 )
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}
var treeWalker = document.createTreeWalker(document.documentElement,
NodeFilter.SHOW_ELEMENT, acceptNode, true );
var outArray = new Array();
if (treeWalker) {
var node = treeWalker.nextNode();
while (node) {
outArray.push(node);
node = treeWalker.nextNode();
}
}
return outArray;
}
ulitimate getElementsByClassName
使用纯dom实现,对ie实现了一些优化
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)
}
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's getElementsByClass
一个纯dom实现
function
getElementsByClass(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;
}
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;
}
prototype1.5的XPath
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;
}
};
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;
}
};
Native firfefox3用C++写的
document.getElementsByClassName
速度对照表
下面我们写一个getElementsByClassName的实现
var getElementsByClassName = function (searchClass, node,tag) {
var classes = searchClass.split(" "),returnElements = [];
if(document.getElementsByClassName){
for(var mm1=0;mm1<classes.length;mm1++)
for(var mm2=0;mm2<document.getElementsByClassName(classes[mm1]).length;mm2++)
returnElements.push(document.getElementsByClassName(classes[mm1])[mm2]);
}else{
node = node || document;
tag = tag || "*";
var 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|$)","i"));
}
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) returnElements.push(current);
}
}
return returnElements;
}
用法:getElementsByClassName("class1 class2")
参数:可接受多个class参数
返回:返回所有包含class1或者class2的元素
var getElementsByClassName = function (searchClass, node,tag) { var classes = searchClass.split(" "),returnElements = []; if(document.getElementsByClassName){ for(var mm1=0;mm1<classes.length;mm1++) for(var mm2=0;mm2<document.getElementsByClassName(classes[mm1]).length;mm2++) returnElements.push(document.getElementsByClassName(classes[mm1])[mm2]); }else{ node = node || document; tag = tag || "*"; var 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|$)","i")); } 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) returnElements.push(current); } } return returnElements; } alert(getElementsByClassName("menu").length) 运行代码