document.getElementsByClassName 的理想实现

2024-05-13 14:48

本文主要是介绍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){//使用document.getElementsByTagName(*)获取所有的元素,然后进行遍历.为了兼容IE5,加document.all分支判断var arrElements=(strTagName=="*"&&oElem.all)?oElem.all:oElem.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毫秒
function getElementsByClassName(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(var 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.lenght;i++){var child=children[i];var classNames=child.className.split(' ');for(var j=0;j<classNames;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毫秒
function getElementsByClassName(searchClass,node,tag){node=node||document;tag=tag||'*';var classes=searchClass.split(' '),patterns="",xhtmlNamespace='http://www.w3c.org/1999/xhtml',namespaceResolver=(document.documentElement.namespaceURI===xhtmlNamespace)?xhtmlNamespace:null,returnElements=[],elements,_node;for(var j=0,jl=classes.length;j<jl;j++){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;};
当然如果游览器原生支持,就用原生的。
document.getElementsByClassName 的理想实现 - 郭培 - 前端工程师 郭培的博客

速度比较一览

document.getElementsByClassName 的理想实现 - 郭培 - 前端工程师 郭培的博客
综合以上方案,我得出了一个最理想的实现——兼容IE5,让后面两个参数是可选的,能原生的原生,利用字面量与倒序循环提高效率……

//查找一网页中5007个类名为“cell”的元素,IE8历时1828 ~ 1844毫秒,
//IE6为125 ~ 172毫秒,IE8为93 ~ 94毫秒,FF3.5为0~1毫秒,opera10为0毫秒,Chrome为1毫秒,
//safari4为0毫秒
function getElementsByClassName(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") ,这三个元素都应该能被检索到!

因此,最最终的方案为:

function getElementsByClassName(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){return returnElements.push(current);}}				}return returnElements;}};

这篇关于document.getElementsByClassName 的理想实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/986008

相关文章

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到