跟随标准与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 继续随着核心类的初始化展开探索其他 ...
随机推荐
- iOS——Swift开发中的单例设计模式(摘译,非原创)
最近在开发一个小的应用,遇到了一些Objective-c上面常用的单例模式,但是swift上面还是有一定区别的,反复倒来倒去发现不能按常理(正常的oc to swift的方式)出牌,因此搜索了一些帖子 ...
- Android 动态获取ListView的高度
public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = l ...
- centos 关闭防火墙
在centos上搭建了个服务器,本机可以访问,局域网无法访问 解决方案:关闭防火墙 sudo systemctl stop firewalld.service 令人恼火的是stop iptables之 ...
- 【UML】UML基础知识
UML简介 统一建模语言(UML)是一个通用的可视化建模语言,用于对软件进行描述.可视化处理.构造和建立软件系统制品的文档. 它记录了对必须构造的系统的决定和理解,可用于对系统的理解. ...
- 25款顶级的jQuery表格插件
jQuery 表格插件可以让你创建各种各样的表格布局,表格布局是报纸和杂志中最常见的布局,现在的网站中也很常见,在这篇文章中,我向大家推荐25个jQuery 的表格插件,你可以任意控制表格的行和列,用 ...
- 关于C++ const 的全面总结
http://blog.csdn.net/Eric_Jo/article/details/4138548 C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方 ...
- c++ string 和wstring 之间的互相转换函数
#include <string> std::string ws2s(const std::wstring& ws) { std::string curLocale = setlo ...
- win10蓝屏问题,关于驱动kisSaasUrlRedirectKnl64.sys 的
上周末刚从win7升级到win10:今天出现了两次蓝屏了,都是显示: xxxxxxx 百度知道链接---http://zhidao.baidu.com/question/164141456570387 ...
- svchost占用内存达1-2G的问题
win7 64位,前一段时间老是如此,很烦,重装,还是有这个问题. 服务中禁用superfect服务,关闭后继续出现1G以上的内存占用,下载svchost viewer检查,发现: 关闭windows ...
- 跨平台web调试代理工具---whistle
whistle是基于Node实现的跨平台web调试代理工具,支持windows.mac.linux等所有安装了Node的操作系统,可以部署在本地机器.虚拟机或远程服务器,并通过本地网页查看或修改HTT ...