zoukankan      html  css  js  c++  java
  • QWrap Selector解密之三:matchesSelector

    QWrap Selector解密之三:matchesSelector

    w3c的selector-api2标准已经提供了matchSelector的相关条文:
    http://dev.w3.org/2006/webapi/selectors-api2/#matchtesting

    module dom {
    [Supplemental]
    interface Element {
    boolean matchesSelector(in DOMString selectors, in optional Element refElement);
    boolean matchesSelector(in DOMString selectors, in sequence<Node> refNodes);
    };
    };


    Firefox也有个对应的方法:https://developer.mozilla.org/en/DOM/Node.mozMatchesSelector,不过,它相对于标准的matchesSelector,明显少了一个refElement的参数。
    QWrap也有一个与标准几乎一致的方法Selector.filter。

    /**
    * 用一个css selector来过滤一个数组.
    * @method filter
    * @static
    * @param {Array|Collection} els: 元素数组
    * @param {string} sSelector: 过滤selector,这个selector里的第一个关系符不可以是“+”“~”。
    * @param {Element} pEl: 父节点。默认是document
    * @returns {Array} : 返回满足过滤条件的元素组成的数组。
    */
    Selector.filter
    = function(els, sSelector, pEl) {
    //...
    }


    与标准相比,不同点有:
    1。标准方法叫matchSelector,这个方法叫filter,用法不同。
    2。sSelector是相对于参考元素的,而不是document,所以,也不必先写:scope伪类。
    3。sSelector的起始关系符需要是亲子关系或后代关系,而不允许是兄弟关系。即,不可以是“+”“~”

    这个方法的思路大略是:取出els[i],然后用sSelector来作路线指导,寻找关系路线,一直找到pEl,找得到,则通过过滤,反之则不通过。
    例如:html结构是这样的:html>body>div#div1.div1>div#div2.div2>span#span1.span1,通过下表我们看下各种情况下的执行过程:

    序号 selector 处理顺序
    1 filter([span1],'span.span3',body) 先判断span1本身是否满足"span.span3",NG
    结论:未通过过滤
    2 filter([span1],'span.span1',body) 先判断span1本身是否满足"span.span1",OK
    再判断body与span1是否是后代关系,OK
    结论:通过过滤
    3 filter([span1],'>span.span1',div2) 先判断span1本身是否满足"span.span1",OK
    再判断div2与span1是否是亲子关系,OK
    结论:通过过滤
    4 filter([span1],'>span.span1',body) 先判断span1本身是否满足"span.span1",OK
    再判断body与span1是否是亲子关系,NG
    结论:未通过过滤

    再看更多层次时,对应的执行过程:

    序号 selector 处理顺序
    11 filter([span1],'div span',body) 先判断span1本身是否满足"span",OK
    通过span1寻找"div ",即找div祖先,得到div2,OK
    再判断body与div2是否是后代关系,OK
    结论:通过过滤
    12 filter([span1],'table span',body) 先判断span1本身是否满足"span",OK
    通过span1寻找"table ",即找table祖先,NG
    结论:未通过过滤
    13 filter([span1],'html span',body) 先判断span1本身是否满足"span",OK
    通过span1寻找"html ",即找html祖先,上寻时通过body时还没找到,NG
    结论:未通过过滤
    注:虽说上寻到body上层可以找到html,但是这也不符合参考body的“ html span”
    14 filter([span1],'>div span',body) 先判断span1本身是否满足"span",OK
    通过span1寻找"div ",即找div祖先,得到div2,OK
    再判断body与div2是否是亲子关系,NG
    回溯,发现可以继续从div2再向上找div,找到div1,OK
    再判断body与div1是否是亲子关系,OK
    结论:通过过滤
    注:这里有一个回溯的过程,即向上寻路时,如果分支不通,需要回退再寻他路。
    注:sizzle没有处理这种回溯的情况,所以某些情况下会出现错误,参见:
    http://www.cnblogs.com/rubylouvre/archive/2011/01/24/1942818.html#2018177
    15 filter([span1],'>div>span',body) 先判断span1本身是否满足"span",OK
    通过span1寻找"div>",即找div父亲,得到div2,OK
    再判断body与div2是否是亲子关系,NG
    结论:未通过过滤
    想一想:为什么这里不需要回溯???
    16 filter([span1],'table div span',body) 先判断span1本身是否满足"span",OK
    通过span1寻找"div ",即找div祖先,得到div2,OK
    通过div2寻找"table ",即找table祖先,NG
    结论:未通过过滤
    想一想:为什么这里不需要回溯???
    17 ... ...



    注,为方便理解,以上例子中都没有提到“+”“~”关系符,有兴趣的同学可以举一反三一下。
    由于回溯是一件很耗cpu的事,所以,我们需要尽量不做无谓的回溯。而是否需要回溯,或在哪一步需要回溯,这个又需要通过整个selector的所有关系符来判断。
    sizzle使用候选集加映射集的方式来实现query,这导致他在作是否回溯的决定时,没法全盘考虑这个selector中的所有关系符以及当前关系符的位置,他很难作这个决定。现在的情形看来,他索性偷了个懒,任何情况下都不作回溯了。----事实上,需要回溯的情况在现实中很少见,所以,Sizzle没有考虑,也很少有人发现这个问题。
    QW.Selector里关于,把“ ”“~”当作需回溯关系符,而把一个selector中的所有关系符串成relationsStr,再通过“(/[+>~] |[+]~/.test(relationsStr))”来判断是否需要回溯。
    例如:
    “ table div span”的关系符串起来是三个空格,(/[+>~] |[+]~/.test(relationsStr))的结果是false,即,不需要回溯;
    “>div>span”的关系符串起来是“>>”,不需要回溯;
    “>div span”的关系符串起来是“> ”,需要回溯;
    ......


    明白了matchesSelector的思路,即“按selector寻路径,将el与pEl连起来”,之后,再看实现代码就会很清晰了。
    事实上,由于这个方法的sSelector参数里可能有“,”并联关系符,所以,真正实现filter的函数是一个内部函数:    (注意一下,参数与filter的参数顺序不一致,而sltors是已经将sSelector拆成了关系符与自选器的配对数组)

    /*
    判断一个长辈与子孙节点是否满足关系要求。----特别说明:这里的第一个关系只能是父子关系,或祖孙关系;
    */
    function filterByRelation(pEl, els, sltors) {
    //...
    }


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

  • 相关阅读:
    生命的等级
    一个笑话
    第一天的日记
    接吻鱼的秘密
    [转载] 女人到底想要什么??
    纪念一塌糊涂bbs
    上海市区找到一处比较便宜的打乒乓地方:)
    朋友在奔驰公司,给我提供的F1照片,奔驰必胜!
    前台mm何处有?
    一个令我感动的女孩!
  • 原文地址:https://www.cnblogs.com/jkisjk/p/qwrap_selector_matchselector.html
Copyright © 2011-2022 走看看