by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=5036
一、时间紧急,废话少说
本文所在的页面藏匿了下面这些代码:
<img id="outside">
<div id="my-id">
<img id="inside">
<div class="lonely"></div>
<div class="outer">
<div class="inner"></div>
</div>
</div>
就是下面这样的表现(为了便于观察,我加了边框背景色和文字):


孤家寡人
outer-inner之间
最内部
首先说点大家都知道的热热身。
querySelector和querySelectorAllIE8+浏览器支持。querySelector返回的是单个DOM元素;querySelectorAll返回的是NodeList.- 我们一般用的多的是
document.querySelectorAll, 实际上,也支持dom.querySelectorAll.例如:document.querySelector("#my-id").querySelectorAll("img")选择的就是里面这个妹子。例如,我在控制台输出该选择
NodeList的长度和id,如下截图:
好了,上面都是众所周知的,好,下面开始展示点有意思的。
大家看下下面2行简单的查询语句:
document.querySelectorAll("#my-id div div");
document.querySelector("#my-id").querySelectorAll("div div");
提问:上面两个语句返回的NodeList的内容是否是一样的?
给大家1分钟的时间思考下。
//zxx: 假设1分钟已经过去了
好了,答案是:不一样的。估计不少人跟我一样,会认为是一样的。
实际上:
document.querySelectorAll("#my-id div div").length === 1;
document.querySelector("#my-id").querySelectorAll("div div").length === 3;
大家如果有疑问,可以在控制台测试下,下图就是我自己测试的结果:

为啥会这样?
第一个符合我们的理解,不解释。那下一个语句,为何返回的NodeList长度是3呢?
首先,遍历该NodeList会发现,查询的三个dom元素为:div.lonely, div.outer, div.inner.
奇怪,奇怪,怎么会是3个呢?
jQuery中有个find()方法,大家很可能受到这个方法影响,导致出现了一些认知的问题:
$("#my-id").find("div div").length === 1;
如果使用find方法,则是1个匹配;由于结构和作用类似,我们很自然疑问原生的querySelectorAll也是这个套路。真是太错特错!!
要解释,为何NodeList长度是3,只要一句话就可以了,我特意加粗标红:
CSS选择器是独立于整个页面的!
什么意思呢?比如说你在页面很深的一个DOM里面写上:
<style>
div div { }
</style>
整个网页,包括父级,只要是满足div div父子关系的元素,全部会被选中,对吧,这个大家应该都清楚的。
这里的querySelectorAll里面的选择器也同样是这也全局特性。document.querySelector("#my-id").querySelectorAll("div div")翻译成白话文就是:查询#my-id的子元素,同时满足整个页面下div div选择器条件的DOM元素们。
我们页面往上滚动看看原始的HTML结构,会发现,在全局视野下,div.lonely, div.outer, div.inner全部都满足div div这个选择器条件,于是,最终返回的长度为3.
二、:scope与区域选择限制
其实,要想querySelectorAll后面选择器不受全局影响,也是有办法的,就是使用目前还处于实验阶段的:scope伪类,其作用就是让CSS是在某一范围内使用。此伪类在CSS中使用是大头,但是也可以在querySelectorAll语句中使用:
document.querySelector("#my-id").querySelectorAll(":scope div div");
兼容性如下:

我写此文时候是15年11月初,目前基本上就FireFox浏览器支持,我估计,以后,会支持越来越多的。为什么呢?
因为Web Components需要它,可以实现真正独立封装,不会受外界影响的HTML组件。
关于:scope目前支持尚浅,时机未到,我就没必要乱展开了,点到为止。
更新于2018-01-09
现在在看我2, 3年前说的上面这段话,发现脸打得啪啪响。:scope伪类看来是支持越来越少了。
更新于2019-02-09
又反转了,:scope伪类在CSS中虽然不支持,但是在querySelectorAll中是有效的。
三、结语还是要的
参考文章:querySelectorAll from an element probably doesn’t do what you think it does
感谢阅读,欢迎纠错,欢迎交流!

//众人: 你丫逗我呢,这也能叫结语……
本文为原创文章,包含脚本行为,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=5036
(本篇完)
相关文章
- 几个常见功能重合DOM API的细节差异 (0.492)
- jQuery诞生记-原理与机制 (0.263)
- 遐想:如果没有IE6和IE7浏览器... (0.254)
- 学会使用CSSStyleSheet构造CSS样式 (0.254)
- 近期手机网页项目一些杂碎心得分享 (0.229)
- 巧用:is()或:where()伪类让scoped的style依然全局匹配 (0.208)
- CSS @scope他来了 (0.208)
- CSS Nesting嵌套与@scope规则也太雷同了吧? (0.208)
- 使用::part伪元素改变Shadow DOM的CSS样式 (0.095)
- 伪元素表单控件默认样式重置与自定义大全 (0.071)
- 小tip: CSS后代选择器可能的错误认识 (RANDOM - 0.025)
























