getElementsByClassName的实现

首先我们看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对比

下面我们写一个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的元素

原文地址:https://www.cnblogs.com/lunalord/p/1987268.html