跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName
按照类名获取元素 -- getElementsByClassName(HTML5)
标准
- WHATWG 在
Document与Element上均有定义,原型HTMLCollection getElementsByClassName(DOMString classNames),并定义了匹配算法和类名的提取算法,注意这里是先从参数里提取出类名作为一个set,然后再开始匹配的。其中指明了在quirks mode下类名大小写不敏感,否则大小写敏感 - DOM 4(
Document,Element)基本和WHATWG一致
注意点
按照标准里的说法,“Unless otherwise stated, a collection must be live. ”。既然标准没有指明getElementsByClassName的返回值说是static的,那么它返回的HTMLCollection就是live的。
WHATWG描述getElementsByClassName的实现是先从参数里用ASCII空白字符分割出类名,将得到的类名组成一个有序集合之后,将能够匹配集合内所有类名的元素返回。除非在quirks mode否则大小写敏感,Document及Element上均有定义。
兼容性
- 属于HTML5新出现的API,IE9+ 及其他浏览器的现行版本均支持
WebKit代码分析
和之前的几个方法一样,在ContainerNode里实现,使用ClassNodeList作为NodeListsNodeData::addCacheWithAtomicName<>的template specialization。之前的一次commit将nodeMatches改为了elementMatches,不过github上的mirror里似乎ClassNodeList还没改掉。ClassNodeList的nodeMatches过滤标准(参考WebCore/dom/ClassNodeList.h)为:
if (!element->hasClass())
return false;
if (!m_classNames.size())
return false;
// FIXME: DOM4 allows getElementsByClassName to return non StyledElement.
// https://bugs.webkit.org/show_bug.cgi?id=94718
if (!element->isStyledElement())
return false;
return element->classNames().containsAll(m_classNames);
可以看到里面目前有个多余的StyledElement判定……这里首先判断要过滤的元素有没有class或者传入的字符串是否不含有效的class,接着检查元素是否为StyledElement(找不到相关文档,不过Node.h里的enum ConstructionType可以看出哪些元素是StyledElement)。
类名的提取实现在SpaceSplitString。ClassNodeList和ElementData均有SpaceSplitString的m_classNames来维护类名集合。这些外部的类通过调用SpaceSplitString::set来更新和设置类名,而SpaceSplitString::set又调用SpaceSplitStringData::create来维护存有集合的私有成员SpaceSplitStringData m_data。
SpaceSplitStringData::create有两个重载,外部调用的是SpaceSplitStringData::create (const AtomicString& keyString)。里面首先调用维护缓存的spaceSplitStringTable(实质是一个static的hashmap)来检查是否已经有缓存,如果没有则开始创建集合。 WebCore/dom/SpaceSplitString.cpp里的tokenizeSpaceSplitString实现了将类名字符串tokenize的算法,并且每分解出一个token,就会调用参数tokenProcessor的processToken。SpaceSplitStringData::create (const AtomicString& keyString)首先以TokenCounter作为tokenProcessor调用tokenizeSpaceSplitString,将类名字符串先扫描一次统计token数目以方便分配内存,接着调用重载的SpaceSplitStringData::create(const AtomicString& keyString, unsigned tokenCount),里面使用TokenAtomicStringInitializer作为tokenProcessor再扫描一次字符串,将每个token的内容保存到分配好的内存里。
判断匹配的算法就比较粗暴了……参见WebCore/dom/SpaceSplitString.cpp的containsAll和WebCore/dom/SpaceSplitString.h的contains会发现,居然是线性查找套线性查找的O(mn)(m和n分别为要查找的类名数和被查找的元素的实际类名数)……不过考虑到应用场景下一般类名很少,多点也就五六个了,被查找的类名可能更少,乘起来mn可能最多也就二三十左右,一般大概不会超过十,此时用高级数据结构带来的overhead可能还大过简单的线性查找,所以这样实现也是合理的。
跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName的更多相关文章
- 跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll
使用CSS选择器获取元素 -- querySelector,querySelectorAll(HTML5) 标准 W3C Selector API Level 1为Document,DocumentF ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByTagName
按照标签名获取元素 -- getElementsByTagName 标准 DOM 1在Element和Document两个interface中均有定义,原型NodeList getElementsBy ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementById
按照ID获取元素 -- getElementById 标准 DOM 1,定义在HTMLDocument Interface 中,原型Element getElementById(in DOMStrin ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName
按照name属性获取多元素 -- getElementsByName 标准 DOM 1 定义在HTMLDocument Interface 中,原型NodeList getElementsByName ...
- ConcurrentHashMap源码探究 (JDK 1.8)
很早就知道在多线程环境中,HashMap不安全,应该使用ConcurrentHashMap等并发安全的容器代替,对于ConcurrentHashMap也有一定的了解,但是由于没有深入到源码层面,很多理 ...
- Vue源码探究-虚拟DOM的渲染
Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...
- Vue源码探究-全局API
Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...
- Vue源码探究-事件系统
Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...
- Vue源码探究-状态初始化
Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...
随机推荐
- SignalR + MVC5 简单示例
本文和前一篇文章很类似,只不过是把 SignalR 应用在了 MVC 中 新建项目,选择 MVC 模板 安装 SignalR Install-Package Microsoft.AspNet.Sign ...
- Spring依赖注入(IOC)那些事
小菜使用Spring有几个月了,但是对于它的内部原理,却是一头雾水,这次借着工作中遇到的一个小问题,来总结一下Spring. Spring依赖注入的思想,就是把对象交由Spring容器管理,使用者只需 ...
- Linux基础精华
Linux基础精华 (继续跟新中...) 常用命令: Linux shell 环境 让你提升命令行效 率的 Bash 快捷键 [完整版] 设置你自己的liux alias Linux的Find使用 L ...
- SVM=LASSO?
SVM和LASSO是机器学习里两个非常经典的模型,每个模型都有大量的文献进行研究.其中去年出版的这本书——<Regularization, Optimization, Kernels, and ...
- Java-认识字符集-转载
问题起源 对于计算机而言,它仅认识两个0和1,不管是在内存中还是外部存储设备上,我们所看到的文字.图片.视频等等“数据”在计算机中都是已二进制形式存在的.不同字符对应二进制数的规则,就是字符的编码.字 ...
- 在ASP.NET MVC5中建置以角色为基础的授权机制
在前一篇贴文中,已探索过如何在MVC5中自定ASP.NET Identity,接下来要来试试在MVC5中如何运用 ASP.NET Identity来设定一个以 "角色"为基础的授权 ...
- Liferay7 BPM门户开发之33: Portlet之间通信的3种方式(session、IPC Render Parameter、IPC Event、Cookies)
文章介绍了5种方式,4种是比较常用的: Portlet session IPC Public Render Parameters IPC Event Cookies 参考地址: https://web ...
- Android:改变Activity切换方式(转载)
overridePendingTransition(enterAnim, exitAnim); Intent intent =new Intent(this,item2.class); startAc ...
- P2P的原理和常见的实现方式(为libjingle开路)
参考原文 为了项目的IM应用,最近在研究libjingle,中间看了也收集了很多资料,感慨网上很多资料要么太过于纠结协议(如STUN.ICE等)实现细节,要么中间有很多纰漏.最后去伪存真,归纳总结了一 ...
- c++ const放置的位置
标准中int const a 与 const int a 是完全等价的.正因为如此,会有很多各种不同的风格,同样的还有"*是跟类型还是变量?",比如char* p与 char *p ...