日期:2014-05-17  浏览次数:20656 次

YUI3 css 选择器实现分析

当然,现代的库都判断了浏览器是否实现了 w3c selector-api ,如果没有才采用下面的方法,目前只有ie系列会执行了。



以前分析过 extjs 的css 选择器实现 ,也粗略看过 jquery的css 选择器实现,这次又看了 yui3的选择器实现,发现每种实现都不同,而yui3或许不是效率最高的一个,却是实现起来最简单的一个。


Extjs 与 Jquery

?

extjs ,jquery都是属于自顶向下的分析方法,不同之处在于jquery将复杂选择符分解为简单单元后直接开始查找,去重,而extjs则分为编译与执行两个阶段,编译期生成对应选择器的dom操作函数,执行器直接执行生成函数即可:


div span


jquery 每次都分析选择器字符串,如分解为为["div","span"],然后再找到页面所有 div,再对这些div的所有子孙span进行合并去重得到最终结果。

extjs 则只有在第一次分析选择符字符串,生成了下列命令组成的函数:

?

alert(Ext.DomQuery.compile("div span"));

//解析 selector 字串在编译期已经做了
//递归也不需要,直接生成调用序列
function (root) {
 var mode;
 ++batch;
 var n = root || document;
 //获取元素
 n = getNodes(n, mode, "div");
 mode = "";
 n = getNodes(n,mode, "span");

 //过滤元素
 return nodup(n);
}

?以后每次相同的选择器字符串只需直接执行函数即可。


对于复杂的选择符,extjs,jquery都需要经过分析,选择,合并,过滤,去重 的阶段。

?

?

?

YUI3 css selector :

?

而 yui3 选择了同以上两者都不同的策略,即自底向上的分析方法,降低了难度,对于


div span


首先分解出单元选择器 ["div","span"] (每个单元有复杂的数据结构),然后取出文档中的所有span元素,再对这些span元素进行过滤,条件为是否父(祖先)元素为div。只需执行过滤操作即可,没有必要执行合并与去重操作。


?

总体来说:yui3 包括 分析与选择,过滤 阶段。代码包括:dom-debug.js,selector-css3-debug.js

?

?

分析:

?

Y.Selector._tokenize 函数,将选择符分解为 combinator 分割的简单选择符,combinator 在css2下面包括

?

combinators: {
            ' ': {
                axis: 'parentNode'
            },

            '>': {
                axis: 'parentNode',
                direct: true
            },


            '+': {
                axis: 'previousSibling',
                direct: true
            }
        },
?

并将它们对应到相应的dom节点的运动方位。


对应简单的选择符yui3其实就分为三类:



属性选择符,其中id,class被简化到这个类别

?

 {
                name: ATTRIBUTES,
                re: /^\[(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
                fn: function(match, token) {
                    var operator = match[2] || '',