sizzle分析记录:关于querySelectorAll兼容问题querySelector和querySelectorAll是W3C提供的
⽬前⼏乎主流浏览器均⽀持了他们。包括 IE8(含) 以上版本、 Firefox、 Chrome、Safari、Opera。
万能的sizzle在⾼版本的浏览器中复杂的选择器尽量⾛querySelectorAll,前提是这个匹配的节点没有兼容问题
从IE8开始虽然⽀持querySelectorAll的API,但是会有各式各样的BUG,所以sizzle拿rbuggyQSA⽤来记录这个BUG问题
if ( support.qsa && (!rbuggyQSA || !st( selector )) ) {
//newContext.querySelectorAll( newSelector )
}
zepto的选择器则更直接
zepto.qsa = function(element, selector) {
var found
return (isDocument(element) && st(selector)) ?
((found = ElementById(RegExp.$1)) ? [found] : []) :
(deType !== 1 && deType !== 9) ? [] :
slice.call(
element.querySelectorAll(selector)
queryselectorall用法)
}
sizzle 2000⾏,zepto直接querySelectorAll接⼝,利弊各⾃评估了
重点就看querySelectorAll的坑到底有哪些?
接⼝定义:
partial interface Document {
Element? querySelector(DOMString selectors);
NodeList querySelectorAll(DOMString selectors);
};
partial interface DocumentFragment {
Element? querySelector(DOMString selectors);
NodeList querySelectorAll(DOMString selectors);
};
partial interface Element {
Element? querySelector(DOMString selectors);
NodeList querySelectorAll(DOMString selectors);
};
从接⼝定义可以看到Document、DocumentFragment、Element都实现了NodeSelector接⼝。即这三种类型的元素都拥有者两个⽅法。querySelector和querySelectorAll的参数须是符合的字符串。
不同的是querySelector返回的是⼀个对象,querySelectorAll返回的⼀个集合(NodeList)。
所以选择querySelectorAll更符合jQuery这个合集对象的习惯
document.querySelectorAll 与 element.querySelectorAll区别?
当调⽤上下为document的时候,没有什么问题,各浏览器的实现基本⼀致
如果调⽤的上下⽂是element,dom Node的时候,浏览器的实现有点不同
具体就是表现在:element.querySelectorAll 在⽂档内全部符合选择器描述的节点包括Element本⾝
<div class= "aaron" id= "aaronId" >
<p><span>内容</span></p>
<div class="text">452</div>
</div>
js
<script type="text/javascript">
var aaElement = ElementById('aaronId');
var element = aaElement.querySelector('.aaron span');
var elementList = document.querySelectorAll('.aaron span');
console.log(element); // <span>Test</span>
console.log(elementList); //
问题出在testElement.querySelector尽然还有返回值!选择上下⽂是在aaElement⾥⾯,选择器是.aaarn就⽗节点,理论是不到对应的节点的
所以逻辑上是不合理的,因为根本不到,但是结果跟document调⽤如出⼀辙,所以此时node ele类似document 了
可能的查机制是这样的:⾸先在document的范围内进⾏查所有满⾜选择器条件的元素,
在上⾯这段代码中,我们的选择器是.aaron span,就是所有的直接⽗元素类名为aaron的元素。
然后,再看哪些元素是调⽤querySelector/querySelectorAll的元素的⼦元素,这些元素将会被返回
这也就说明了为什么aaElement会⼀同返回
那么针对这种情况如何兼容?
程序员的智慧总是⽆穷的, Andrew Dupont提出了⼀个解决⽅案,来⾃jQuery2.1.1
先看看jQuery最终的实现newContext.querySelectorAll⽤的上下⽂调⽤
if ( newSelector ) {
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch(qsaError) {
} finally {
if ( !old ) {
}
}
}
代码可见newContext可能是document || 提供的⼀个上下⽂
如:$("#aaronId").find("div[class='text']) 此时的上下⽂即是$("#aaronId")节点
jQuery(element).find(selector) 在⽂档内全部符合选择器描述的节点不包括Element本⾝注意finally总是执⾏veAttribute("id"),意味着我们在之前的处理强制加了⼀个id
反推hack的⼿法,selectors前⾯指定上下⽂的的id,限制匹配的范围
版本各有实现的不同,但是我们⽬前最终版为标准2.1.1
IE 8 :不⽀持上下⽂为object;
if ( nodeType === 1 && LowerCase() !== "object" ) {
groups = tokenize( selector );
if ( (old = Attribute("id")) ) {
nid = place( rescape, "\\$&" );
} else {
context.setAttribute( "id", nid );
}
nid = "[id='" + nid + "'] ";
i = groups.length;
while ( i-- ) {
groups[i] = nid + toSelector( groups[i] );
}
newContext = st( selector ) && testContext( context.parentNode ) || context; newSelector = groups.join(",");
}
1. 关键是给context设置⼀个id
所以上下⽂content,就会存在这个id限制范围
2. 拼接出查询的选择器,附上这个ID前缀
newSelector: "[id='sizzle-1405486760710'] div[class='text']"
3. 查询
newContext.querySelectorAll( newSelector )
4. 因为强制加了ID,所以需要删除
这样就达到⽬的范围限制:context.querySelectorAll了
querySelectorAll在选择器上存在的问题,具体我是看jQuery的源码相关处理,基本都是IE8上的问题jQuery对兼容的判断,都是采⽤的功能判断直接特性检测,伪造⼀个真实的环境测试⽀持度
针对querySelectorAll选取存在的问题之后分析
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论