querySelector和querySelectorAll同属于Selectors API Level 1规范,该规范早在2006年就已经开始发展,并在2007年10月形成querySelector(All)的雏形。由于规范发展的够早,所以除了IE6、7以外,所有浏览器都基本支持。这两个方法可以作用到Element、Document、DocumentFragment实例上面,即:
var elem = document.getElementById("test"),
frag = document.createDocumentFragment(); frag.appendChild(document.createElement("div")); elem.querySelector("p");// Element, querySelectorAll document.querySelector("div");// Document, querySelectorAll
document.body.querySelector("div");// querySelectorAll frag.querySelector("div");// documentFragment, querySelectorAll

方法接收唯一的一个参数,该参数可为任意合法的CSS选择器字符串。不过在IE8下,对于大部分的CSS3选择器都不支持(只支持相邻兄弟element1~element2;属性选择器[attr^=val][attr$=val],[attr*=val])。除此之外,如果想要在IE8下使用伪元素选择器,需要用:,而不是CSS3规定的::(css3选择器的浏览器支持参考:http://caniuse.com/#search=nth-of-type)。

Selectors API返回的内容是静态的NodeList,而非实时更新的NodeList,这和get系列(早期的chrome等浏览器返回的是NodeList,现在已经改为HTMLCollection实例。NodeList和HTMLCollection最大的不同就是NodeList可包括文本、注释等非元素节点,而HTMLCollection只包括元素节点)、document.images返回动态的集合(HTMLCollection)以及childNodes(NodeList)是不一样的。

Selectors API虽然好用,不过在使用的时候还是需要注意一些问题。以下面代码为例:

<body>
<div id="test"><p>test</p></div>
</body>
var ele = document.getElementById("test");
ele.querySelector("div p").length; // A
jQuery(ele).find("div p").length; // B
ele.querySelector("body p").length; // C
jQuery(ele).find("body p").length; // D

对于代码A,返回值为1,;代码B,返回值为0。代码C,返回值仍为1;代码D,返回值为0。(结果适用于所有支持Selectors API的浏览器)

对于习惯使用jQuery的人来说,上面的结果可能有点接受不了。不过在规范中明确写明:

Even though the method is invoked on an element, selectors are still evaluated in the context of the entire document. In the following example, the method will still match the div element's child p element, even though the body element is not a descendant of the div element itself.

var div = document.getElementById("bar");
var p = div.querySelector("body p");
      一句话,Selectors API选择器的查找范围仍旧是document,只不过在查找完毕之后会判断元素是否位于ele的子树中。elem.querySelector(All)(str)相当于document.querySelector(All)(str)和elem子树的交集。
      个人猜想,W3C设计Selectors API的初衷就是为了达到和在CSS样式表中写相同的css Selector选中的元素完全相同的效果。而在样式表中,并没有作用范围的概念,所有css选择器的“作用域”都是整个文档(:scope除外,该伪元素可以指定css选择器的作用范围。目前IE、opera不支持)。
 
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
      google了一下,翻到了jQuery作者在08年关于这个问题的一篇文章(http://ejohn.org/blog/thoughts-on-queryselectorall)。John Resig和Prototype、Dojo的作者都认为Selector API没有作用范围是个明显的错误。文章里面还有john和规范制定者的一些关于这个问题的来往邮件,有兴趣的话可以看一下(http://lists.w3.org/Archives/Public/public-webapi/2008Apr/thread.html#msg251)。
 
      我想,这也是w3c制定Selectors API Level 2的原因。在这个规范中,提出了find、findAll方法,实际上就和jQuery的find方法效果一致了,这两个方法目前还没有浏览器支持。除此之外,还有一个matches方法,用于判断元素是否和选择器匹配,该方法在各个浏览器的实现为(https://developer.mozilla.org/en-US/docs/Web/API/Element.matches):
      
 
      在jQuery1.4.2以及之前的版本的Sizzle实现中,只使用了document.querySelectorAll这个方法。在1.4.3以后开始使用elem.querySeectorAll。为了避免作用范围的问题,jQuery在使用该方法时先定了必须是元素才可使用该方法,然后首先把该元素的原有id存到一个变量里面,接着将元素ID设为"__sizzle__",最后在选择器中手动添加ID来限定选择范围。操作完之后再把ID设为原来的值(原来没有ID则直接remove掉)。代码如下:
                                // qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
// and working up from there (Thanks to Andrew Dupont for the technique)
// IE 8 doesn't work on object elements
} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
var old = context.id, id = context.id = "__sizzle__"; try {
return makeArray( context.querySelectorAll( "#" + id + " " + query ), extra ); } catch(pseudoError) {
} finally {
if ( old ) {
context.id = old; } else {
context.removeAttribute( "id" );
}
}
}

不过,如果文档中真的有的元素id为“__sizzle__”,这个方法应该就会悲剧了。

在zepto中,并没有针对elem使用querySelector(All)时的特殊处理,So:

<!DOCTYPE html>
<html>
<head>
<script src="http://zeptojs.com/zepto.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="a"><div><p></p></div></div>
</body>
<script>
var ele = Zepto("#a").find("body div div p");
alert(ele.length); // 1
</script>
</html>
希望zepto可以尽快修改这个问题,以求达到从jQuery到Zepto更好的迁移。
 
这个问题很多人早就发现了,这有篇文章,也是说的这个问题:
这篇文章写的稍微有点不对,就是在所有浏览器下的NodeList实例(childNodes、querySelectorAll)是没办法使用query方法的:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="a"><div><p></p></div></div>
</body>
<script>
var ele =document.getElementById("a").querySelectorAll("*");
var chd = document.getElementById("a").childNodes;
alert(ele.querySelectorAll); // undefined
alert(chd.querySelectorAll); // undefined
</script>
</html>

深入理解querySelector(All)的更多相关文章

  1. 深入理解javascript选择器API系列第三篇——h5新增的3种selector方法

    × 目录 [1]方法 [2]非实时 [3]缺陷 前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuer ...

  2. HTML5中类jQuery选择器querySelector的使用

    简介 HTML5向Web API新引入了document.querySelector以及document.querySelectorAll两个方法用来更方便地从DOM选取元素,功能类似于jQuery的 ...

  3. javascript选择器querySelector和querySelectorAll的使用和区别

    querySelector 和 querySelectorAll 方法是 W3C Selectors API规范中定义的.他们的作用是根据 CSS 选择器规范,便捷定位文档中指定元素. 目前几乎主流浏 ...

  4. querySelector和querySelectorAll

    jQuery被开发者如此的青睐和它强大的选择器有很大关系,比起笨重的document.getElementById.document.getElementByName… ,查找元素很方便,其实W3C中 ...

  5. 原生的强大DOM选择器querySelector

    在传统的 JavaScript 开发中,查找 DOM 往往是开发人员遇到的第一个头疼的问题,原生的 JavaScript 所提供的 DOM 选择方法并不多,仅仅局限于通过 tag, name, id ...

  6. 深入理解JavaScript 事件

    本文总结自<JavaScript高级程序设计>以及自己平时的经验,针对较新浏览器以及 DOM3 级事件标准(2016年8月),对少部分内容作了更正,增加了各种例子及解析. 如无特殊说明,本 ...

  7. 新增的querySelector、querySelectorAll测试

    从IE9开始DOM开始支持支持CSS的选择器了,DOM提供了两个接口 querySelector 得到一个DOM querySelectorAll 得到一组DOM 一个个的解释这些选择器也没有必要,我 ...

  8. HTML5中querySelector()和querySelectorAll()

    HTML5向Web API新引入了document.querySelector以及document.querySelectorAll两个方法用来更方便地从DOM选取元素,功能类似于jQuery的选择器 ...

  9. 理解JavaScript中的事件路由冒泡过程及委托代理机制

    当我用纯CSS实现这个以后.我开始用JavaScript和样式类来完善功能. 然后,我有一些想法,我想使用Delegated Events (事件委托)但是我不想有任何依赖,插入任何库,包括jQuer ...

随机推荐

  1. 关于开发板不能ping通外网IP

    最近在做远程监控的项目,打算用开发板给一个网站发送数据包.不过发现开发板只能ping通同一局域网内的ip,外网的ip不能ping通.纠结了半天发现是网关没有设置的原因.下面来说说如何解决这个问题. 首 ...

  2. STL_iterator迭代器(1)——迭代器的分类

    一.容器迭代器 尽管C++指针也是迭代器,但用的更多的是容器迭代器.容器迭代器用法和iterdemo.cpp一样,但和将迭代器申明为指针变量不同的是,你可以使用容器类方法来获取迭代器对象.两个典型的容 ...

  3. RMQ——[USACO Jan07] 均衡队形题解

    题目:[USACO Jan07] 均衡队形 描述: 题目描述 农夫约翰的 N (1 ≤ N ≤ 50,000) 头奶牛,每天挤奶时总会按同样的顺序站好.一日,农夫约翰决定为奶牛们举行一个“终极飞盘”比 ...

  4. Selenium webdriver 开始

    最早接触的selenium是 selenium IDE,当时是为了准备论文.为了用IDE还下载了Firefox浏览器.后来接触过两个项目都需要selenium,一个采用selenium webdirv ...

  5. Java的多线程(上)

    多线程的优点和必要性是不言而喻的. 三种方法实现多线程 1. 继承Thread class A extends Thread{ public void run() {...} } 使用时, new A ...

  6. js打开新的链接2

    window.open打开新的连接时可能会被浏览器拦截掉. 所以采用动态创建a标签的形式. var a = document.createElement('a');  a.href = myUrl;  ...

  7. hdu3308LCIS(线段树,点更新,段查寻,查寻时一定要注意跨越时如何计算)

    Problem Description Given n integers. You have two operations: U A B: replace the Ath number by B. ( ...

  8. Android手机令牌教程

    Android手机令牌教程 "沉下心,你不再是小孩子了.多看书,学做人"-JeffLi告诉自己 Written In The Font 花了一个天一夜,搞了这个小东西-安卓手机令牌 ...

  9. Spine(2D骨骼动画)

    点击进入Spine官网 Spine 是一款针对游戏的 2D 骨骼动画编辑工具. Spine 旨在提供更高效和简洁 的工作流程,以创建游戏所需的动画. 功能: 1.摄影表 Dopesheet 在动画制作 ...

  10. 怎样用Google APIs和Google的应用系统进行集成(3)----调用Google 发现(Discovery)API的RESTful服务

    说了这么多,那么首先同意我以Google Discovery RESTful服务为例,给大家演示怎样用最普通的Java代码调用Google Discovery RESTful服务. 引言: 在&quo ...