跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll
使用CSS选择器获取元素 -- querySelector
,querySelectorAll
(HTML5)
标准
- W3C Selector API Level 1为
Document
,DocumentFragment
和Element
追加了querySelector
和querySelctorAll
,原型为Element? querySelector(DOMString selectors)
和NodeList querySelectorAll(DOMString selectors)
,说明了匹配的算法 - W3C Selector API 2又追加了
find
和findAll
,但目前在各大浏览器里暂无实现(这个标准目前还未进入recommendation)。 - WHATWG DOM 将
querySelector
及querySelectorAll
定义在了interface ParentNode
并声明Document
,DocumentFragment
及Element
均需实现这个interface,原型为Element? querySelector(DOMString selectors)
与[NewObject] NodeList querySelectorAll(DOMString selectors)
,并定义了scope-match
的步骤。注意interface ParentNode
还有用于获取相对位置的元素的两个方法query
和queryAll
,但目前在各大浏览器里暂无实现。 - DOM4也新增了
interface ParentNode
,和WHATWG类似
注意点
- 标准里强调了
querySelectorAll
返回的一定是一个staticNodeList
-- 也就是说如果将它的返回结果保存下来,当文档更新时,保存的NodeList
里的元素不会跟着更新。 - W3C Selector API Level 1 规定当传入的CSS选择器不合法时,会抛出
SYNTAX_ERR
异常。Selector API Level 2 和 WHATWG 改为了SyntaxError
。 - 按照W3C Selector API Level 1的提示,在选择器里使用pseudo-elements(目前只有
:after
,:before
,:first-letter
,:first-line
,:selection
)将不会匹配到任何元素,另外出于保护隐私的考虑,标准也推荐将所有链接视为未访问,即:visited
不会匹配到任何元素。 - 无匹配元素时,
querySelector
返回null
,querySelectorAll
返回空的NodeList
- 有多个匹配元素时,
querySelector
返回按照document order(先序DFS)遍历到的第一个元素,querySelectorAll
返回按照 document order 排序的NodeList
兼容性
IE 9+及其他浏览器的现行版本正常支持包括CSS3的选择器,IE8支持简单的 CSS2 选择器(如:不支持空格表示的后代)
WebKit 代码分析
ContainerNode
就是 WHATWG 里描述的 interface ParentNode
,ContainerNode
的querySelector
和querySelctorAll
实际上分别调用SelectorQuery
的queryFirst
和queryAll
(参考WebCore/dom/ContainerNode.cpp),它们又分别调用SelectorDataList
的queryFirst
和queryAll
(注意这里的 queryAll
和标准里定义的不是一个东西。另外 SingleElementExtractorSelectorQueryTrait
和AllElementExtractorSelectorQueryTrait
这两个使用模版达到类似动态类型的写法挺有趣的),通过execute
来对ContainerNode
的子节点匹配CSS。execute
里就是CSS选择器的代码,里面还有相当一部分 JIT 的优化,这里就不展开分析了。
在queryFirst
用于SelectorQueryTrait
的 template specialiation 的 SingleElementExtractorSelectorQueryTrait
里,shouldOnlyMatchFirstElement
设为true
,注意execute
用于匹配CSS的其他方法基本都会在第一次找到匹配元素的时候检查shouldOnlyMatchFirstElement
确定是否立刻保存匹配结果并返回(使用elementDescendants
达到先序DFS,elementDescendants
最终也是和getElementsByID
的实现一样使用到了NodeTraversal
),这样就达到了标准里提到的返回先序DFS遇到的第一个匹配元素的要求。而queryAll
使用了StaticElementList
(StaticNodeList
),来为保存匹配元素的Vector
(属于WTF)创建一个 static 的快照用于返回(参见WebCore/dom/SelectorQuery.cpp)
NCZ的博客上讨论了为何StaticNodeList
会相对慢很多(不过上面用的是几年前的代码,现在的代码用的是WTF的Vector
的swap
(底层调用std::swap
)通过交换元素来实现复制,参见Source/WTF/wtf/Vector.h)
jQuery也有一个关于querySelectorAll
性能问题的 Open issue。
跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll的更多相关文章
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName
按照类名获取元素 -- getElementsByClassName(HTML5) 标准 WHATWG 在Document与Element上均有定义,原型 HTMLCollection getElem ...
- 跟随标准与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 继续随着核心类的初始化展开探索其他 ...
随机推荐
- Linux:目录&文件基本操作
- 表示上一次所在目录,- 通常表示当前用户的"home"目录.使用 pwd 命令可以获取当前所在路径(绝对路径). 新建文件:touch test创建目录:mkdir -p fa ...
- javascript跨域通信(一):利用location.hash实现跨域iframe自适应
页面域关系: a.html所属域A:www.A.comb.html所属域B:www.B.com 问题本质: js对跨域iframe访问问题,因为要控制a.html中iframe的高度和宽度就必须首先读 ...
- 为什么要设置getter和setter?
面向对象语言中,通常把属性设置为私有,然后添加getter和setter方法来访问.有人说,这本质上和设置属性为公有没有区别,干脆把属性public算了.也有人反驳,这样做破坏了封装.但是,破坏了封装 ...
- AngularJS应用页面切换优化方案
葡萄城的一款尚在研发中的产品,对外名称暂定为X项目.其中使用了已经上市的Wijmo中SpreadJS产品,另外,在研发过程中整理了一些研发总结分享给大家.如本篇的在页面切换的过程中优化方案,欢迎大家跟 ...
- C#与数据库访问技术总结(八)之ExecuteNonQuery方法
ExecuteNonQuery方法 ExecuteNonQuery方法主要用来更新数据. 通常使用它来执行Update.Insert和Delete语句. 该方法返回值意义如下: 对于Update.In ...
- paip.java OutOfMemoryError 解决方法o33
paip.java OutOfMemoryError 解决方法o33 java.lang.OutOfMemoryError: Requested # java.lang.OutOfMemoryErro ...
- 诚聘Android开发工程师
职位要求1.有1年以上Android应用项目经验或相关经验: 2.熟悉Android操作系统和Android SDK,GUI编程及GDI的使用:熟练掌握Android 的 UI 系统控件及常用布局.动 ...
- “代理XP”组件已作为此服务器安全配置的一部分被关闭的解决办法
代理XP”组件已作为此服务器安全配置的一部分被关闭.系统管理员可以使用sp_configure来启用“代理XP”.有关启用“代理XP”的详细信息,请参阅SQL Server联机丛书中的“外围应用配置器 ...
- 安装redis监控
在修改登录中心的时候,数据存储在redis里面,需要对redis进行监控,使用的是Redis-Live 参考文章: http://www.nkrode.com/article/real-time-da ...
- Mac OS 下安装wget
环境: Mac OS X 10.9.4 1 下载源码 地址: http://ftp.gnu.org/gnu/wget/wget-1.9.tar.gz 2 解压安装 tar zxvf wget-1.9 ...