使用CSS选择器获取元素 -- querySelectorquerySelectorAll(HTML5)

标准

  • W3C Selector API Level 1DocumentDocumentFragmentElement追加了querySelectorquerySelctorAll,原型为Element? querySelector(DOMString selectors)NodeList querySelectorAll(DOMString selectors),说明了匹配的算法
  • W3C Selector API 2又追加了findfindAll,但目前在各大浏览器里暂无实现(这个标准目前还未进入recommendation)。
  • WHATWG DOM 将querySelectorquerySelectorAll定义在了interface ParentNode并声明Document, DocumentFragmentElement均需实现这个interface,原型为Element? querySelector(DOMString selectors)[NewObject] NodeList querySelectorAll(DOMString selectors),并定义了scope-match的步骤。注意interface ParentNode还有用于获取相对位置的元素的两个方法queryqueryAll,但目前在各大浏览器里暂无实现。
  • DOM4也新增了interface ParentNode,和WHATWG类似

注意点

  • 标准里强调了querySelectorAll返回的一定是一个static NodeList -- 也就是说如果将它的返回结果保存下来,当文档更新时,保存的NodeList里的元素不会跟着更新。
  • W3C Selector API Level 1 规定当传入的CSS选择器不合法时,会抛出SYNTAX_ERR异常。Selector API Level 2WHATWG 改为了 SyntaxError
  • 按照W3C Selector API Level 1的提示,在选择器里使用pseudo-elements(目前只有:after:before:first-letter:first-line:selection)将不会匹配到任何元素,另外出于保护隐私的考虑,标准也推荐将所有链接视为未访问,即:visited不会匹配到任何元素。
  • 无匹配元素时,querySelector返回nullquerySelectorAll返回空的NodeList
  • 有多个匹配元素时,querySelector返回按照document order(先序DFS)遍历到的第一个元素,querySelectorAll返回按照 document order 排序的NodeList

兼容性

IE 9+及其他浏览器的现行版本正常支持包括CSS3的选择器,IE8支持简单的 CSS2 选择器(如:不支持空格表示的后代)

WebKit 代码分析

ContainerNode 就是 WHATWG 里描述的 interface ParentNodeContainerNodequerySelectorquerySelctorAll实际上分别调用SelectorQueryqueryFirstqueryAll(参考WebCore/dom/ContainerNode.cpp),它们又分别调用SelectorDataListqueryFirstqueryAll(注意这里的 queryAll 和标准里定义的不是一个东西。另外 SingleElementExtractorSelectorQueryTraitAllElementExtractorSelectorQueryTrait这两个使用模版达到类似动态类型的写法挺有趣的),通过execute来对ContainerNode的子节点匹配CSS。execute里就是CSS选择器的代码,里面还有相当一部分 JIT 的优化,这里就不展开分析了。

queryFirst用于SelectorQueryTrait的 template specialiation 的 SingleElementExtractorSelectorQueryTrait里,shouldOnlyMatchFirstElement设为true,注意execute用于匹配CSS的其他方法基本都会在第一次找到匹配元素的时候检查shouldOnlyMatchFirstElement确定是否立刻保存匹配结果并返回(使用elementDescendants达到先序DFS,elementDescendants最终也是和getElementsByID的实现一样使用到了NodeTraversal),这样就达到了标准里提到的返回先序DFS遇到的第一个匹配元素的要求。而queryAll使用了StaticElementListStaticNodeList),来为保存匹配元素的Vector(属于WTF)创建一个 static 的快照用于返回(参见WebCore/dom/SelectorQuery.cpp

NCZ的博客上讨论了为何StaticNodeList会相对慢很多(不过上面用的是几年前的代码,现在的代码用的是WTF的Vectorswap(底层调用std::swap)通过交换元素来实现复制,参见Source/WTF/wtf/Vector.h

jQuery也有一个关于querySelectorAll性能问题的 Open issue

跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll的更多相关文章

  1. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName

    按照类名获取元素 -- getElementsByClassName(HTML5) 标准 WHATWG 在Document与Element上均有定义,原型 HTMLCollection getElem ...

  2. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByTagName

    按照标签名获取元素 -- getElementsByTagName 标准 DOM 1在Element和Document两个interface中均有定义,原型NodeList getElementsBy ...

  3. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementById

    按照ID获取元素 -- getElementById 标准 DOM 1,定义在HTMLDocument Interface 中,原型Element getElementById(in DOMStrin ...

  4. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName

    按照name属性获取多元素 -- getElementsByName 标准 DOM 1 定义在HTMLDocument Interface 中,原型NodeList getElementsByName ...

  5. ConcurrentHashMap源码探究 (JDK 1.8)

    很早就知道在多线程环境中,HashMap不安全,应该使用ConcurrentHashMap等并发安全的容器代替,对于ConcurrentHashMap也有一定的了解,但是由于没有深入到源码层面,很多理 ...

  6. Vue源码探究-虚拟DOM的渲染

    Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...

  7. Vue源码探究-全局API

    Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...

  8. Vue源码探究-事件系统

    Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...

  9. Vue源码探究-状态初始化

    Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...

随机推荐

  1. Javascript--练习(包括主界面图片轮播效果)

    练习一 例子1:做一个问题,如果输入的答案正确则弹出正确,错误弹出错误: 这里在text里面写了一个daan属性,里面存了答案的值,点击检查答案的时候cheak输入的内容和答案是否一样: Body中代 ...

  2. 【系统移植】JNI

    jni代码 java调用jni的接口: 1, 调用动态库 static{   System.loadLibrary("led_jni");  // system/lib/lible ...

  3. duilib进阶教程 -- 各种控件的响应 (10)

    到上一个教程为止,界面显示的代码就都介绍完啦,现在开始介绍控件的响应,其实在<2013 duilib入门简明教程 -- 事件处理和消息响应 (17)>里已经列出了duilib自己定义的所有 ...

  4. iOS开发-UITableView顶部图片下拉放大

    关于顶部图片下拉放大,在用户展示的个人中心显示用户个人头像信息,设置UITableView的headerView实现,UITableView继承自UIScrollView,同样的设置UIScrollV ...

  5. Python面试题(一)

    **晚上在公司的论坛上看到一道面试题,题目如下:随机给定一字符串和字符,要求重排,比如:'abde','c'.重排之后变成'abcde' **看到他们给的答案很多都是二分法重排,既然是字符类的处理,当 ...

  6. NGUI ScrollView 循环 Item 实现性能优化

    今天来说说一直都让我在项目中头疼的其中一个问题,NGUI 的scrollView 列表性能问题,实现循环使用item减少性能上的开销. 希望能够给其他同学们使用和提供一个我个人的思路,这个写的不是太完 ...

  7. FreeSwitch安装配置记录

    安装FreeSwitch 主要命令如下: git clone -b v1.2.stable git://git.freeswitch.org/freeswitch.gitcd freeswitch/. ...

  8. python之对指定目录文件夹的批量重命名

    python之对指定目录文件夹的批量重命名 import os,shutil,string dir = "/Users/lee0oo0/Documents/python/test" ...

  9. Avizo - 高级三维可视化及分析软件

    今天从材料科学应用角度介绍Avizo的基本功能. Avizo是一款先进的三维可视化及分析应用,可用来探索从断层扫描.显微镜.核磁共振成像及更多其他技术获得的材料科学数据.从简单的可视化与测量到高级的图 ...

  10. django 注册、登录及第三方接口程序(4):扩展邮箱注册,登录,微博登录

    1.邮箱注册 这里需要扩展User,两种解决办法,1,注册时将email字段内容赋给username,这种瞒天过海型的,另一种就是扩展user,这里介绍django1.5的扩展方法. 1.settin ...