首先我们看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;
}
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)
}
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;
}
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;
}
};
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的元素