深入理解querySelector(All)
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 childp
element, even though thebody
element is not a descendant of thediv
element itself.var div = document.getElementById("bar"); var p = div.querySelector("body p");
// 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>
<!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>