QWrap Selector解密之一:认识selector写法

QWrap使用了一个独立的QW.Selector,而不是借用sizzle。
相对于sizzle,QW.Selector摈弃了isXml参数(无情抛弃)与selector群组除重排序(实用意义有限而效率影响太大);提供query方法之外,还提供了filter等与selector有关的其它一些方法,(详见:QW Selector简介);比sizzle更严谨的对待需要回溯的selector(详见:jquery delegate美中不足);体积小于sizzle的70%;性能也相当。两年来虽说没啥大变化,现在看来也不见得比当今的sizzle逊色,所以QWrap在开源时,也决定继续使用它。
业界关心Selector实现的同学很少,自己实现过Selector的人数就更不用说,可还是有同学建议我写一些关于selector实现的文章。
尽管也不会有几个读者有兴趣,但是,从思维沉淀出文章,对自己本人来说,也是一件挺有意义的事,所以,还是费点心思写一写吧。

先来认识一下这个选择器甲:“textarea,#myId>input.date[type=text]:enabled”
其中的“,”是并联关系符,它把选择器甲拆成选择器甲A“textarea”甲B“#myId>input.date[type=text]:enabled”两个选择器。
并联的意思是:如是一个元素符合甲A或甲B,那么这个元素满足甲。

含有并联关系符“,”的选择器,叫选择器群组。它也是广义的选择器。
而选择器甲A与甲B,是独立选择器

认识一下选择器甲B:“#myId>input.date[type=text]:enabled”
其中的“>”是亲子关系符,它把甲B拆分成选择器甲B1“#myId”甲B2“input.date[type=text]:enabled”两个选择器。
css3一共有五个关系符(combinator):
“,” 并联关系符(优先级最高),“div,span”表示div或span
“ ” 后代关系符,“div span”表示div的span后代
“>” 亲子关系符,“div>span”表示div的span儿子
“+” 相邻兄弟关系符,“div+span”表示div的相邻的span弟弟
“~” 兄弟关系符,“A~B”表示div的span弟弟
这里,把不含关系符的选择器叫自选器,例如甲A“textarea”、甲B1“#myId”、甲B2“input.date[type=text]:enabled

认识一下自选器甲B2“input.date[type=text]:enabled”
表示“tagName是INPUT”并且“className含有date”并且“[type=text]”并且“:enable”
它们可以分成三类:
写法快捷选择器:包括*、tagName、#id、.className四种
属性选择器:被方括号括起
伪类选择器:以冒号加伪类名表示,对于支持参数的伪类,用括号括起参数,例如“:nth-child(odd)”

通常,理解这么多,我们写css就差不多够了。
但是,很多同学对选择符有一个误解,这误解导致我们在解密选择器的实现时,先就有了一个结。
问题1:选择器甲B“#myId>input.date[type=text]:enabled”里面有几个自选器,有几个关系符?
----很自然的回答是:两个自选器,一个关系符。
问题2:选择器“#myId div>input.date[type=text]:enabled”里面有几个自选器,有几个关系符?
----很自然的回答是:三个自选器,两个关系符。
问题3:为什么自选器要比关系符多一个?
----为什么呢!!那我们再重新来认识一下独立选择器。

先看一下querySelectorAll方法标准
The querySelectorAll() method on the NodeSelector interface must, when invoked,
return a NodeList containing all of the matching Element nodes within the node’s subtrees, in document order. If there are no such nodes, the method must return an empty NodeList.
意译为:返回匹配selector的子节点集合。
但是它没有说明,这个selector的参考起点。
例如,对于这样的树结构:html>body>div#div1>div#div2
document.getElementById('div1').querySelectorAll('div');//这个很清晰,返回的是:[div#div2]
document.getElementById('div1').querySelectorAll('div div');//这个呢?返回的是:[div#div2],还是空集合[]?
事实上,浏览器原生的,返回的都是[div#div2];而jquery的$('#div1').find('div div'),返回的是空集合(低于1.6的jquery存在使用原生querySelectorAll不一致的问题)。
也就是说,它实现的情况是标准里的这种用法的结果一致:
document.getElementById('div1').querySelectorAll(':scope div div'); (注:scope伪类参见:http://dev.w3.org/2006/webapi/selectors-api2/#the-scope-pseudo-class
也就是说,jquery在传入的selector参数前默认加上了:scope
所以,jquery也可以这么用:
$('#div1').css('color','red').find('>div').css('color','blue');
QWrap的策略与jquery的一致,QW中对应的用法是:
W('#div1').css('color','red').query('>div').css('color','blue');
第二个selector是“>div”,它有一个自选器,有一个关系符,即:自选器数并不比关系符数多。

现在,我们重新来回答这个问题:选择器甲B“#myId>input.date[type=text]:enabled”里面有几个自选器,有几个关系符?
----我会回答,在#myId前,其实还应该有一个“ ”后代关系符,不过,我们把它省略掉了。也就是:它有两个自选器,两个关系符,不过,书写时省掉了开头的那个后代关系符。

附:QWrap网址:http://www.qwrap.com

posted on 2011-05-21 16:38  JKisJK  阅读(2156)  评论(1编辑  收藏  举报

导航