现有这样一段HTML:
<div id="div1">
<span class="a">a1</span>
<span class="b">b1</span>
<span class="c">c1</span>
<div id="div2">
<span class="a">a2</span>
<span class="b">b2</span>
<span class="c">c2</span>
</div>
</div>
现在用js去查找元素
jQuery
$('div .a, div .b, div .c',$('#div1'))
Sizzle
Sizzle('div .a, div .b, div .c',Sizzle('#div1'))
根据你的想象,上述js代码将返回哪些元素呢?
你可能想,要么就是所有的span,要么就是后面3个span,但其实是返回除了第一个span之外的所有span!
jQuery 1.4.3 到当前最新的 1.7.2 都存在该问题,但1.4.2没有该BUG.
分析了一下jQuery/Sizzle的源码,就明白了。
jquery-1.7.2.js 第5163行, 或者sizzle.js第1221行:
return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
针对上面的例子,等价于
document.getElementById('div1').querySelectorAll("[id='div1'] div .a, div .b, div .c")
第一段是[id='div1'] div .a, 第二段是div .b, 第三段是div .c 所以导致第一个span被排除,第2第3个却未被排除。
弄清了原因,修正就很简单了,在query表达式每个逗号后面都加上[id=xxx] 的限定就行了。
好在是开源的,我已经在github向jquery/sizzle提交了pull request。
我把这句改成了如下:
return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query.replace(/\,/g,",[id='" + nid + "'] ") ), extra );
测试通过。