zoukankan      html  css  js  c++  java
  • QWrap Selector简介

    #
    看到最近司徒同学发了好几篇与selector有关的文章。就也草写一篇有关selector的一些杂想。

    以QWrap.Selector为例,它提供的几个方法。
    query(refEl, sSelector)
    one(refEl, sSelector)
    filter(els, sSelector, pEl)
    selector2Filter(sSelector)
    test(el, sSelector)

    代码
    /**
    * 以refEl为参考,得到符合过滤条件的HTML Elements. refEl可以是element或者是document
    * @method query
    * @static
    * @param {HTMLElement} refEl: 参考对象
    * @param {string} sSelector: 过滤selector,
    * @returns {array} : 返回elements数组。
    * @example:
    var els=query(document,"li input.aaa");
    for(var i=0;i<els.length;i++ )els[i].style.backgroundColor='red';
    */
    query:
    function(refEl,sSelector){
    //...
    }


    query(refEl,sSelector)是对refEl.querySelectorAll(sSelector)方法的模拟。对象方法变成静态方法,将对象变成静态方法的第一个参数。
    市面上的selector,通常把refEl当第二个参数,如:Sizzle = function(selector, context, ...)。
    可能是因为Sizzle考虑到易用性,所以倒装了一下。JK不赞成这种做法,觉得易用性应该是jquery考虑的,而不应该是由sizzle考虑。

    先说明一下selector的语法。
    A: 复杂selector
    一个复杂的selector可以由“,”来分割成多个简单的selector。元素满足其中的一个简单selector,即通过筛选。
    例如“div a, div input[type=button]”可以折成“div a”与“div input[type=button]”。
    如果分开query,然后相关,那么理论上就会需要进行“并集除重”“排序”两个操作。
    除重与排序会损失一些性能,需要权衡利弊(当然可以多添些代码来减小损失)。例如,QWrap放弃了在存在“,”对除重与排序的严谨性追求。

    B: 简单selector
    把没有“,”的selector当作简单selector。
    例如:“div.aaa”“div a.aaa”“div>a.aaa”
    css2+css3,一共有四种关系符:
    “ ”----子孙
    “>”----儿子
    “+”----最大的弟弟
    “~”----所有的弟弟
    例如:一个var els=QW.Selector.query(document.body,"div>a")
    它的意思是:在document.body下找,父亲是<div>的<a>元素。

    C:最简单selector。
    我们把没有关系符的selector叫最简单selector。
    例如:
    “input.aaa[readOnly]”
    “input:nth-last-child(2n)”
    “.aaa”


    我们再看下简单“B: 简单selector”。
    例如“div>a.aaa”
    它是由两个最简selector中间夹一个关系符组成,这是我们直观的看到的情况。
    为什么最简selector有两个,而关系符只有一个?
    为什么?
    因为它省略了第一个关系符“ ”
    即,理论上,它应该这么写“ div>a.aaa”。
    在css的selector中,可能很少有第一个关系符是非“ ”的情况,但是在js里,却是很常用的功能。
    例如,QW里的用法:W('ul.aaa').delegate('>li','click',func)。它的意思是,为ul.aaa元素加上事件代理,代理只针对它们的直接儿子li,而不是针对它子子孙孙里所有的li。
    ----注:jquery对这种情况,写法似复要复杂一些。略过jquery的相关写法。

    由于第一个关系符不一定是“ ”,所以,对于从右到左的selector实现方来式说,需要特别处理。
    例如:<span onclick="alert('找我的弟弟:'+QW.Selector.query(this,'+span'));">点我</span><span>要找的人</span>

    代码
    /**
    * 以refEl为参考,得到符合过滤条件的一个元素. refEl可以是element或者是document
    * @method one
    * @static
    * @param {HTMLElement} refEl: 参考对象
    * @param {string} sSelector: 过滤selector,
    * @returns {HTMLElement} : 返回element,如果获取不到,则反回null。
    * @example:
    var els=query(document,"li input.aaa");
    for(var i=0;i<els.length;i++ )els[i].style.backgroundColor='red';
    */
    one:
    function(refEl,sSelector){
    //...
    }


    one(refEl,sSelector)是对refEl.querySelector(sSelector)方法的模拟。对象方法变成静态方法,将对象变成静态方法的第一个参数。
    获取得到一个满足sSelector的元素。
    QW.Selector偷懒,直接用query(refEl,sSelector)[0]。这样会有很大的性能损失。以后再说。
    另外,浏览器返回的是第一个满足条件的元素。而QW.Selector在有“,”关系符时,由于没有排序,所以不能保证返回的是第一个。


    代码
    /**
    * 判断一个元素是否符合某selector.
    * @method test
    * @static
    * @param {HTMLElement} el: 被考察参数
    * @param {string} sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")
    * @returns {function} : 返回过滤函数。
    */
    test:
    function(el,sSelector){
    //...
    }


    test(el,sSelector)方法是判断一个元素是否满足一个最简单的selector。
    例如元素el=<div class="aaa bbb"/>满足test(el,'div.aaa'),但是不满足test(el,'div.ccc')。

    代码
    /**
    * 用一个css selector来过滤一个数组.
    * @method filter
    * @static
    * @param {Array|Collection} els: 元素数组
    * @param {string} sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")
    * @param {Element} pEl: 父节点。默认是document.documentElement
    * @returns {Array} : 返回满足过滤条件的元素组成的数组。
    */
    filter:
    function(els,sSelector,pEl){
    //...
    },


    filter(els,sSelector,pEl)是以pEl为参考对象,用sSelector来过滤els。
    在备注文档里说是“sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")”
    是因为目前代码还没有考虑完全。例如:如果第一个关系符是“+”或“~”时。
    QWrap的dom模块里,某些情况下,有使用“>div aaa”等存在关系符的情形。

    代码
    /**
    * 把一个selector字符串转化成一个过滤函数.
    * @method selector2Filter
    * @static
    * @param {string} sSelector 过滤selector,这个selector里没有关系运算符(", >+~")
    * @returns {function} : 返回过滤函数。
    * @example:
    var fun=selector2Filter("input.aaa");alert(fun);
    */
    selector2Filter:
    function(sSelector){
    return s2f(sSelector);
    },


    selector2Filter(sSelector)是把一个最简的selector字符串转化成一个过滤函数。
    例如,selector2Filter("div[readOnly]"),会返回以下function:
    function(el){
        return el.tagName=='DIV' && !!el.readOnly;
    }
    在QW.NodeH里的以下方法中会用到
    QW.NodeH.ancestorNode(el,sSelector)
    QW.NodeH.nextSibling(el,sSelector)
    QW.NodeH.previsouSibling(el,sSelector)
    例如。QW.NodeH.previsouSibling(el,'div')会返回以el为参考元素,离他最近的<div>兄长。

    另外,Selector的效率,一直是一个很热的话题。
    QWrap里面也有效率比赛。参见resource/js/_tools/speedmatch/_examples/SelectorSpeed.html
    QWrap的selector的效率,在不改代码结构的情形下,还可以进行改进,不过有时很懒,觉得现在在使用的项目中,没人报效率问题,所以,就把它给忽略了。

    附:
    1. QWrap:http://github.com/wedteam/qwrap

    2. QW.Selector的无依赖版代码:

    代码
    /*
    Copyright (c) 2009, Baidu Inc. All rights reserved.
    version: $version$ $release$ released
    author: yingjiakuan@baidu.com
    */

    var QW={};

    /**
    * @class Selector Css Selector相关的几个方法
    * @singleton
    * @namespace QW
    */
    (
    function(){
    var trim=function(s){
    return s.replace(/^\s+|\s+$/g, "");
    },
    mulReplace
    =function (s,arr){
    for(var i=0;i<arr.length;i++) s=s.replace(arr[i][0],arr[i][1]);
    return s;
    },
    encode4Js
    =function(s){
    return mulReplace(s,[
    [
    /\\/g,"\\u005C"],
    [
    /"/g,"\\u0022"],
    [
    /'/g,"\\u0027"],
    [
    /\//g,"\\u002F"],
    [/\r/g,"\\u000A"],
    [
    /\n/g,"\\u000D"],
    [
    /\t/g,"\\u0009"]
    ]);
    };

    var Selector={
    /**
    * @property {int} queryStamp 最后一次查询的时间戳,扩展伪类时可能会用到,以提速
    */
    queryStamp:
    0,
    /**
    * @property {Json} _operators selector属性运算符
    */
    _operators:{
    //以下表达式,aa表示attr值,vv表示比较的值
    '': 'aa',//isTrue|hasValue
    '=': 'aa=="vv"',//equal
    '!=': 'aa!="vv"', //unequal
    '~=': 'aa&&(" "+aa+" ").indexOf(" vv ")>-1',//onePart
    '|=': 'aa&&(aa+"-").indexOf("vv-")==0', //firstPart
    '^=': 'aa&&aa.indexOf("vv")==0', // beginWith
    '$=': 'aa&&aa.lastIndexOf("vv")==aa.length-"vv".length', // endWith
    '*=': 'aa&&aa.indexOf("vv")>-1' //contains
    },
    /**
    * @property {Json} _shorthands 缩略写法
    */
    _shorthands: [
    [
    /\#([\w\-]+)/g,'[id="$1"]'],//id缩略写法
    [/^([\w\-]+)/g, function(a,b){return '[tagName="'+b.toUpperCase()+'"]';}],//tagName缩略写法
    [/\.([\w\-]+)/g, '[className~="$1"]'],//className缩略写法
    [/^\*/g, '[tagName]']//任意tagName缩略写法
    ],
    /**
    * @property {Json} _pseudos 伪类逻辑
    */
    _pseudos:{
    "first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
    "last-child":function(a){return !(a=a.nextSibling) || !a.tagName && !a.nextSibling;},
    "only-child":function(a){return getChildren(a.parentNode).length==1;},
    "nth-child":function(a,nth){return checkNth(a,nth); },
    "nth-last-child":function(a,nth){return checkNth(a,nth,true); },
    "first-of-type":function(a){ var tag=a.tagName; var el=a; while(el=el.previousSlibling){if(el.tagName==tag) return false;} return true;},
    "last-of-type":function(a){ var tag=a.tagName; var el=a; while(el=el.nextSibling){if(el.tagName==tag) return false;} return true; },
    "only-of-type":function(a){var els=a.parentNode.childNodes; for(var i=els.length-1;i>-1;i--){if(els[i].tagName==a.tagName && els[i]!=a) return false;} return true;},
    "nth-of-type":function(a,nth){var idx=1;var el=a;while(el=el.previousSibling) {if(el.tagName==a.tagName) idx++;} return checkNth(idx,nth); },//JK:懒得为这两个伪类作性能优化
    "nth-last-of-type":function(a,nth){var idx=1;var el=a;while(el=el.nextSibling) {if(el.tagName==a.tagName) idx++;} return checkNth(idx,nth); },//JK:懒得为这两个伪类作性能优化
    "empty":function(a){ return !a.firstChild; },
    "parent":function(a){ return !!a.firstChild; },
    "not":function(a,sSelector){ return !s2f(sSelector)(a); },
    "enabled":function(a){ return !a.disabled; },
    "disabled":function(a){ return a.disabled; },
    "checked":function(a){ return a.checked; },
    "contains":function(a,s){return (a.textContent || a.innerText || "").indexOf(s) >= 0;}
    },
    /**
    * @property {Json} _attrGetters 常用的Element属性
    */
    _attrGetters:
    function(){
    var o={'class': 'el.className',
    'for': 'el.htmlFor',
    'href':'el.getAttribute("href",2)'};
    var attrs='name,id,className,value,selected,checked,disabled,type,tagName,readOnly,offsetWidth,offsetHeight'.split(',');
    for(var i=0,a;a=attrs[i];i++) o[a]="el."+a;
    return o;
    }(),
    /**
    * @property {Json} _relations selector关系运算符
    */
    _relations:{
    //寻祖
    "":function(el,filter,topEl){
    while((el=el.parentNode) && el!=topEl){
    if(filter(el)) return el;
    }
    return null;
    },
    //寻父
    ">":function(el,filter,topEl){
    el
    =el.parentNode;
    return el!=topEl&&filter(el) ? el:null;
    },
    //寻最小的哥哥
    "+":function(el,filter,topEl){
    while(el=el.previousSibling){
    if(el.tagName){
    return filter(el) && el;
    }
    }
    return null;
    },
    //寻所有的哥哥
    "~":function(el,filter,topEl){
    while(el=el.previousSibling){
    if(el.tagName && filter(el)){
    return el;
    }
    }
    return null;
    }
    },
    /**
    * 把一个selector字符串转化成一个过滤函数.
    * @method selector2Filter
    * @static
    * @param {string} sSelector 过滤selector,这个selector里没有关系运算符(", >+~")
    * @returns {function} : 返回过滤函数。
    * @example:
    var fun=selector2Filter("input.aaa");alert(fun);
    */
    selector2Filter:
    function(sSelector){
    return s2f(sSelector);
    },
    /**
    * 判断一个元素是否符合某selector.
    * @method test
    * @static
    * @param {HTMLElement} el: 被考察参数
    * @param {string} sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")
    * @returns {function} : 返回过滤函数。
    */
    test:
    function(el,sSelector){
    return s2f(sSelector)(el);
    },
    /**
    * 用一个css selector来过滤一个数组.
    * @method filter
    * @static
    * @param {Array|Collection} els: 元素数组
    * @param {string} sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")
    * @param {Element} pEl: 父节点。默认是document.documentElement
    * @returns {Array} : 返回满足过滤条件的元素组成的数组。
    */
    filter:
    function(els,sSelector,pEl){
    var sltors=splitSelector(sSelector);
    return filterByRelation(pEl||document.documentElement,els,sltors);
    },
    /**
    * 以refEl为参考,得到符合过滤条件的HTML Elements. refEl可以是element或者是document
    * @method query
    * @static
    * @param {HTMLElement} refEl: 参考对象
    * @param {string} sSelector: 过滤selector,
    * @returns {array} : 返回elements数组。
    * @example:
    var els=query(document,"li input.aaa");
    for(var i=0;i<els.length;i++ )els[i].style.backgroundColor='red';
    */
    query:
    function(refEl,sSelector){
    Selector.queryStamp
    = queryStamp++;
    refEl
    =refEl||document.documentElement;
    var els=nativeQuery(refEl,sSelector);
    if(els) return els;//优先使用原生的
    var groups=trim(sSelector).split(",");
    els
    =querySimple(refEl,groups[0]);
    for(var i=1,gI;gI=groups[i];i++){
    var els2=querySimple(refEl,gI);
    els
    =els.concat(els2);
    //els=union(els,els2);//除重会太慢,放弃此功能
    }
    return els;
    },
    /**
    * 以refEl为参考,得到符合过滤条件的一个元素. refEl可以是element或者是document
    * @method one
    * @static
    * @param {HTMLElement} refEl: 参考对象
    * @param {string} sSelector: 过滤selector,
    * @returns {HTMLElement} : 返回element,如果获取不到,则反回null。
    * @example:
    var els=query(document,"li input.aaa");
    for(var i=0;i<els.length;i++ )els[i].style.backgroundColor='red';
    */
    one:
    function(refEl,sSelector){
    var els=Selector.query(refEl,sSelector);
    return els[0];
    }


    };

    window.__SltPsds
    =Selector._pseudos;//JK 2010-11-11:为提高效率
    /*

    retTrue 一个返回为true的函数
    */
    function retTrue(){
    return true;
    }

    /*
    arrFilter(arr,callback) : 对arr里的元素进行过滤
    */
    function arrFilter(arr,callback){
    var rlt=[],i=0;
    if(callback==retTrue){
    if(arr instanceof Array) return arr.slice(0);
    else{
    for(var len=arr.length;i<len;i++) {
    rlt[i]
    =arr[i];
    }
    }
    }
    else{
    for(var oI;oI=arr[i++];) {
    callback(oI)
    && rlt.push(oI);
    }
    }
    return rlt;
    };

    var elContains,//部分浏览器不支持contains(),例如FF
    getChildren,//部分浏览器不支持children,例如FF3.5-
    hasNativeQuery,//部分浏览器不支持原生querySelectorAll(),例如IE8-
    findId=function(id) {return document.getElementById(id);};

    (
    function(){
    var div=document.createElement('div');
    div.innerHTML
    ='<div class="aaa"></div>';
    hasNativeQuery
    =(div.querySelectorAll && div.querySelectorAll('.aaa').length==1);
    elContains
    =div.contains?
    function(pEl,el){ return pEl!=el && pEl.contains(el);}:
    function(pEl,el){ return (pEl.compareDocumentPosition(el) & 16);};
    getChildren
    =div.children?
    function(pEl){ return pEl.children;}:
    function(pEl){
    return arrFilter(pEl.childNodes,function(el){return el.tagName;});
    };
    })();


    function checkNth(el,nth,reverse){
    if(nth=='n') return true;
    if(typeof el =='number') var idx=el;
    else{
    var pEl=el.parentNode;
    if(pEl.__queryStamp!=queryStamp){
    var els=getChildren(pEl);
    for(var i=0,elI;elI=els[i++];){
    elI.__siblingIdx
    =i;
    };
    pEl.__queryStamp
    =queryStamp;
    pEl.__childrenNum
    =i-1;
    }
    if(reverse) idx=pEl.__childrenNum-el.__siblingIdx+1;
    else idx=el.__siblingIdx;
    }
    switch (nth)
    {
    case 'even':
    case '2n':
    return idx%2==0;
    case 'odd':
    case '2n+1':
    return idx%2==1;
    default:
    if(!(/n/.test(nth))) return idx==nth;
    var arr=nth.replace(/(^|\D+)n/g,"$11n").split("n"),
    k
    =arr[0]|0,
    kn
    =idx-arr[1]|0;
    return k*kn>=0 && kn%k==0;
    }
    }
    /*
    * s2f(sSelector): 由一个selector得到一个过滤函数filter,这个selector里没有关系运算符(", >+~")
    */
    var filterCache={};
    function s2f(sSelector,isForArray){
    if(!isForArray && filterCache[sSelector]) return filterCache[sSelector];
    var pseudos=[],//伪类数组,每一个元素都是数组,依次为:伪类名/伪类值
    attrs=[],//属性数组,每一个元素都是数组,依次为:属性名/属性比较符/比较值
    s=trim(sSelector);
    s
    =s.replace(/\:([\w\-]+)(\(([^)]+)\))?/g,function(a,b,c,d,e){pseudos.push([b,d]);return "";});//伪类
    for(var i=0,shorthands=Selector._shorthands,sh;sh=shorthands[i];i++)
    s
    =s.replace(sh[0],sh[1]);
    //var reg=/\[\s*([\w\-]+)\s*([!~|^$*]?\=)?\s*(?:(["']?)([^\]'"]*)\3)?\s*\]/g; //属性选择表达式解析
    var reg=/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/g; //属性选择表达式解析,thanks JQuery
    s=s.replace(reg,function(a,b,c,d,e){attrs.push([b,c||"",e||""]);return "";});//普通写法[foo][foo=""][foo~=""]等
    if(!(/^\s*$/).test(s)) {
    throw "Unsupported Selector:\n"+sSelector+"\n-"+s;
    }

    var sFun=[];
    for(var i=0,attr;attr=attrs[i];i++){//属性过滤
    var attrGetter=Selector._attrGetters[attr[0]] || 'el.getAttribute("'+attr[0]+'")';
    sFun.push(Selector._operators[attr[
    1]].replace(/aa/g,attrGetter).replace(/vv/g,attr[2]));
    }
    for(var i=0,pI;pI=pseudos[i];i++) {//伪类过滤
    if(!Selector._pseudos[pI[0]]) throw "Unsupported Selector:\n"+pI[0]+"\n"+s;
    if(/^(nth-|not|contains)/.test(pI[0])){
    sFun.push(
    '__SltPsds["'+pI[0]+'"](el,"'+encode4Js(pI[1])+'")');
    }
    else{
    sFun.push(
    '__SltPsds["'+pI[0]+'"](el)');
    }
    }
    if (sFun.length)
    {
    if(isForArray){
    return new Function('els','var els2=[];for(var i=0,el;el=els[i++];){if('+sFun.join('&&')+') els2.push(el);} return els2;');
    }
    else{
    return filterCache[sSelector]=new Function('el','return '+sFun.join('&&')+';');
    }
    }
    else {
    if(isForArray){
    return function(els){return arrFilter(els,retTrue);}
    }
    else{
    return filterCache[sSelector]=retTrue;
    }

    }
    };

    /*
    * {int} xxxStamp: 全局变量查询标记
    */
    var queryStamp=0,
    relationStamp
    =0,
    querySimpleStamp
    =0;

    /*
    * nativeQuery(refEl,sSelector): 如果有原生的querySelectorAll,并且只是简单查询,则调用原生的query,否则返回null.
    * @param {Element} refEl 参考元素
    * @param {string} sSelector selector字符串
    * @returns
    */
    function nativeQuery(refEl,sSelector){
    if(hasNativeQuery && /^((^|,)\s*[.\w-][.\w\s\->+~]*)+$/.test(sSelector)) {
    //如果浏览器自带有querySelectorAll,并且本次query的是简单selector,则直接调用selector以加速
    //部分浏览器不支持以">~+"开始的关系运算符
    var arr=[],els=refEl.querySelectorAll(sSelector);
    for(var i=0,elI;elI=els[i++];) arr.push(elI);
    return arr;
    }
    return null;
    };

    /*
    * querySimple(pEl,sSelector): 得到pEl下的符合过滤条件的HTML Elements.
    * sSelector里没有","运算符
    * pEl是默认是document.body
    * @see: query。
    */
    function querySimple(pEl,sSelector){
    querySimpleStamp
    ++;
    /*
    为了提高查询速度,有以下优先原则:
    最优先:原生查询
    次优先:在' '、'>'关系符出现前,优先正向(从祖到孙)查询
    次优先:id查询
    次优先:只有一个关系符,则直接查询
    最原始策略,采用关系判断,即:从最底层向最上层连线,能连得成功,则满足条件
    */

    //最优先:原生查询
    var els=nativeQuery(pEl,sSelector);
    if(els) return els;//优先使用原生的


    var sltors=splitSelector(sSelector),
    pEls
    =[pEl],
    i,
    elI,
    pElI;

    var sltor0;
    //次优先:在' '、'>'关系符出现前,优先正向(从上到下)查询
    while(sltor0=sltors[0]){
    if(!pEls.length) return [];
    var relation=sltor0[0];
    els
    =[];
    if(relation=='+'){//第一个弟弟
    filter=s2f(sltor0[1]);
    for(i=0;elI=pEls[i++];){
    while(elI=elI.nextSibling){
    if(elI.tagName){
    if(filter(elI)) els.push(elI);
    break;
    }
    }
    }
    pEls
    =els;
    sltors.splice(
    0,1);
    }
    else if(relation=='~'){//所有的弟弟
    filter=s2f(sltor0[1]);
    for(i=0;elI=pEls[i++];){
    if(i>1 && elI.parentNode==pEls[i-2].parentNode) continue;//除重:如果已经query过兄长,则不必query弟弟
    while(elI=elI.nextSibling){
    if(elI.tagName){
    if(filter(elI)) els.push(elI);
    }
    }
    }
    pEls
    =els;
    sltors.splice(
    0,1);
    }
    else{
    break;
    }
    }
    var sltorsLen=sltors.length;
    if(!sltorsLen || !pEls.length) return pEls;

    //次优先:idIdx查询
    for(var idIdx=0,id;sltor=sltors[idIdx];idIdx++){
    if((/^[.\w-]*#([\w-]+)/i).test(sltor[1])){
    id
    =RegExp.$1;
    sltor[
    1]=sltor[1].replace('#'+id,'');
    break;
    }
    }
    if(idIdx<sltorsLen){//存在id
    var idEl=findId(id);
    if(!idEl) return [];
    for(i=0,pElI;pElI=pEls[i++];){
    if(elContains(pElI,idEl)) {
    els
    =filterByRelation(pEl,[idEl],sltors.slice(0,idIdx+1));
    if(!els.length || idIdx==sltorsLen-1) return els;
    return querySimple(idEl,sltors.slice(idIdx+1).join(',').replace(/,/g,' '));
    }
    }
    return [];
    }

    //---------------
    var getChildrenFun=function(pEl){return pEl.getElementsByTagName(tagName);},
    tagName
    ='*',
    className
    ='';
    sSelector
    =sltors[sltorsLen-1][1];
    sSelector
    =sSelector.replace(/^[\w\-]+/,function(a){tagName=a;return ""});
    if(hasNativeQuery){
    sSelector
    =sSelector.replace(/^[\w\*]*\.([\w\-]+)/,function(a,b){className=b;return ""});
    }
    if(className){
    getChildrenFun
    =function(pEl){return pEl.querySelectorAll(tagName+'.'+className);};
    }

    //次优先:只剩一个'>'或' '关系符(结合前面的代码,这时不可能出现还只剩'+'或'~'关系符)
    if(sltorsLen==1){
    if(sltors[0][0]=='>') {
    getChildrenFun
    =getChildren;
    var filter=s2f(sltors[0][1],true);
    }
    else{
    filter
    =s2f(sSelector,true);
    }
    els
    =[];
    for(i=0;pElI=pEls[i++];){
    els
    =els.concat(filter(getChildrenFun(pElI)));
    }
    return els;
    }


    //走第一个关系符是'>'或' '的万能方案
    sltors[sltors.length-1][1] = sSelector;
    els
    =[];
    for(i=0;pElI=pEls[i++];){
    els
    =els.concat(filterByRelation(pElI,getChildrenFun(pElI),sltors));
    }
    return els;
    };


    function splitSelector(sSelector){
    var sltors=[];
    var reg=/(^|\s*[>+~ ]\s*)(([\w\-\:.#*]+|\([^\)]*\)|\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\6|)\s*\])+)(?=($|\s*[>+~ ]\s*))/g;
    var s=trim(sSelector).replace(reg,function(a,b,c,d){sltors.push([trim(b),c]);return "";});
    if(!(/^\s*$/).test(s)) {
    throw "Unsupported Selector:\n"+sSelector+"\n--"+s;
    }
    return sltors;
    }

    /*
    判断一个长辈与子孙节点是否满足关系要求。----特别说明:这里的第一个关系只能是父子关系,或祖孙关系;
    */

    function filterByRelation(pEl,els,sltors){
    relationStamp
    ++;
    var sltor=sltors[0],
    len
    =sltors.length,
    needNotTopJudge
    =!sltor[0],
    filters
    =[],
    relations
    =[],
    needNext
    =[],
    relationsStr
    ='';

    for(var i=0;i<len;i++){
    sltor
    =sltors[i];
    filters[i]
    =s2f(sltor[1],i==len-1);//过滤
    relations[i]=Selector._relations[sltor[0]];//寻亲函数
    if(sltor[0]=='' || sltor[0]=='~') needNext[i]=true;//是否递归寻亲
    relationsStr+=sltor[0]||' ';
    }
    els
    =filters[len-1](els);//自身过滤
    if(len==1) return els;
    if(/[+>~] |[+]~/.test(relationsStr)){//需要回溯
    //alert(1); //用到这个分支的可能性很注。放弃效率的追求。
    function chkRelation(el){//关系人过滤
    var parties=[],//中间关系人
    j=len-1,
    party
    =parties[j]=el;
    for(;j>-1;j--){
    if(j>0){//非最后一步的情况
    party=relations[j](party,filters[j-1],pEl);
    }
    else if(needNotTopJudge || party.parentNode==pEl){//最后一步通过判断
    return true;
    }
    else {//最后一步未通过判断
    party=null;
    }
    while(!party){//回溯
    if(++j==len) { //cache不通过
    return false;
    }
    if(needNext[j]) {
    party
    =parties[j-1];
    j
    ++;
    }
    }
    parties[j
    -1]=party;
    }
    };
    return arrFilter(els,chkRelation);
    }
    else{//不需回溯
    var els2=[];
    for(var i=0,el,elI; el=elI=els[i++] ; ) {
    for(var j=len-1;j>0;j--){
    if(!(el=relations[j](el,filters[j-1],pEl))) {
    break;
    }
    }
    if(el && (needNotTopJudge || el.parentNode==pEl)) els2.push(elI);
    }
    return els2;
    }

    }

    QW.Selector
    =Selector;
    })();

    /*
    Copyright (c) 2009, Baidu Inc. All rights reserved.
    version: $version$ $release$ released
    author: yingjiakuan@baidu.com
    */

    var QW={};

    /**
    * @class Selector Css Selector相关的几个方法
    * @singleton
    * @namespace QW
    */
    (
    function(){
    var trim=function(s){
    return s.replace(/^\s+|\s+$/g, "");
    },
    mulReplace
    =function (s,arr){
    for(var i=0;i<arr.length;i++) s=s.replace(arr[i][0],arr[i][1]);
    return s;
    },
    encode4Js
    =function(s){
    return mulReplace(s,[
    [
    /\\/g,"\\u005C"],
    [
    /"/g,"\\u0022"],
    [
    /'/g,"\\u0027"],
    [
    /\//g,"\\u002F"],
    [/\r/g,"\\u000A"],
    [
    /\n/g,"\\u000D"],
    [
    /\t/g,"\\u0009"]
    ]);
    };

    var Selector={
    /**
    * @property {int} queryStamp 最后一次查询的时间戳,扩展伪类时可能会用到,以提速
    */
    queryStamp:
    0,
    /**
    * @property {Json} _operators selector属性运算符
    */
    _operators:{
    //以下表达式,aa表示attr值,vv表示比较的值
    '': 'aa',//isTrue|hasValue
    '=': 'aa=="vv"',//equal
    '!=': 'aa!="vv"', //unequal
    '~=': 'aa&&(" "+aa+" ").indexOf(" vv ")>-1',//onePart
    '|=': 'aa&&(aa+"-").indexOf("vv-")==0', //firstPart
    '^=': 'aa&&aa.indexOf("vv")==0', // beginWith
    '$=': 'aa&&aa.lastIndexOf("vv")==aa.length-"vv".length', // endWith
    '*=': 'aa&&aa.indexOf("vv")>-1' //contains
    },
    /**
    * @property {Json} _shorthands 缩略写法
    */
    _shorthands: [
    [
    /\#([\w\-]+)/g,'[id="$1"]'],//id缩略写法
    [/^([\w\-]+)/g, function(a,b){return '[tagName="'+b.toUpperCase()+'"]';}],//tagName缩略写法
    [/\.([\w\-]+)/g, '[className~="$1"]'],//className缩略写法
    [/^\*/g, '[tagName]']//任意tagName缩略写法
    ],
    /**
    * @property {Json} _pseudos 伪类逻辑
    */
    _pseudos:{
    "first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
    "last-child":function(a){return !(a=a.nextSibling) || !a.tagName && !a.nextSibling;},
    "only-child":function(a){return getChildren(a.parentNode).length==1;},
    "nth-child":function(a,nth){return checkNth(a,nth); },
    "nth-last-child":function(a,nth){return checkNth(a,nth,true); },
    "first-of-type":function(a){ var tag=a.tagName; var el=a; while(el=el.previousSlibling){if(el.tagName==tag) return false;} return true;},
    "last-of-type":function(a){ var tag=a.tagName; var el=a; while(el=el.nextSibling){if(el.tagName==tag) return false;} return true; },
    "only-of-type":function(a){var els=a.parentNode.childNodes; for(var i=els.length-1;i>-1;i--){if(els[i].tagName==a.tagName && els[i]!=a) return false;} return true;},
    "nth-of-type":function(a,nth){var idx=1;var el=a;while(el=el.previousSibling) {if(el.tagName==a.tagName) idx++;} return checkNth(idx,nth); },//JK:懒得为这两个伪类作性能优化
    "nth-last-of-type":function(a,nth){var idx=1;var el=a;while(el=el.nextSibling) {if(el.tagName==a.tagName) idx++;} return checkNth(idx,nth); },//JK:懒得为这两个伪类作性能优化
    "empty":function(a){ return !a.firstChild; },
    "parent":function(a){ return !!a.firstChild; },
    "not":function(a,sSelector){ return !s2f(sSelector)(a); },
    "enabled":function(a){ return !a.disabled; },
    "disabled":function(a){ return a.disabled; },
    "checked":function(a){ return a.checked; },
    "contains":function(a,s){return (a.textContent || a.innerText || "").indexOf(s) >= 0;}
    },
    /**
    * @property {Json} _attrGetters 常用的Element属性
    */
    _attrGetters:
    function(){
    var o={'class': 'el.className',
    'for': 'el.htmlFor',
    'href':'el.getAttribute("href",2)'};
    var attrs='name,id,className,value,selected,checked,disabled,type,tagName,readOnly,offsetWidth,offsetHeight'.split(',');
    for(var i=0,a;a=attrs[i];i++) o[a]="el."+a;
    return o;
    }(),
    /**
    * @property {Json} _relations selector关系运算符
    */
    _relations:{
    //寻祖
    "":function(el,filter,topEl){
    while((el=el.parentNode) && el!=topEl){
    if(filter(el)) return el;
    }
    return null;
    },
    //寻父
    ">":function(el,filter,topEl){
    el
    =el.parentNode;
    return el!=topEl&&filter(el) ? el:null;
    },
    //寻最小的哥哥
    "+":function(el,filter,topEl){
    while(el=el.previousSibling){
    if(el.tagName){
    return filter(el) && el;
    }
    }
    return null;
    },
    //寻所有的哥哥
    "~":function(el,filter,topEl){
    while(el=el.previousSibling){
    if(el.tagName && filter(el)){
    return el;
    }
    }
    return null;
    }
    },
    /**
    * 把一个selector字符串转化成一个过滤函数.
    * @method selector2Filter
    * @static
    * @param {string} sSelector 过滤selector,这个selector里没有关系运算符(", >+~")
    * @returns {function} : 返回过滤函数。
    * @example:
    var fun=selector2Filter("input.aaa");alert(fun);
    */
    selector2Filter:
    function(sSelector){
    return s2f(sSelector);
    },
    /**
    * 判断一个元素是否符合某selector.
    * @method test
    * @static
    * @param {HTMLElement} el: 被考察参数
    * @param {string} sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")
    * @returns {function} : 返回过滤函数。
    */
    test:
    function(el,sSelector){
    return s2f(sSelector)(el);
    },
    /**
    * 用一个css selector来过滤一个数组.
    * @method filter
    * @static
    * @param {Array|Collection} els: 元素数组
    * @param {string} sSelector: 过滤selector,这个selector里没有关系运算符(", >+~")
    * @param {Element} pEl: 父节点。默认是document.documentElement
    * @returns {Array} : 返回满足过滤条件的元素组成的数组。
    */
    filter:
    function(els,sSelector,pEl){
    var sltors=splitSelector(sSelector);
    return filterByRelation(pEl||document.documentElement,els,sltors);
    },
    /**
    * 以refEl为参考,得到符合过滤条件的HTML Elements. refEl可以是element或者是document
    * @method query
    * @static
    * @param {HTMLElement} refEl: 参考对象
    * @param {string} sSelector: 过滤selector,
    * @returns {array} : 返回elements数组。
    * @example:
    var els=query(document,"li input.aaa");
    for(var i=0;i<els.length;i++ )els[i].style.backgroundColor='red';
    */
    query:
    function(refEl,sSelector){
    Selector.queryStamp
    = queryStamp++;
    refEl
    =refEl||document.documentElement;
    var els=nativeQuery(refEl,sSelector);
    if(els) return els;//优先使用原生的
    var groups=trim(sSelector).split(",");
    els
    =querySimple(refEl,groups[0]);
    for(var i=1,gI;gI=groups[i];i++){
    var els2=querySimple(refEl,gI);
    els
    =els.concat(els2);
    //els=union(els,els2);//除重会太慢,放弃此功能
    }
    return els;
    },
    /**
    * 以refEl为参考,得到符合过滤条件的一个元素. refEl可以是element或者是document
    * @method one
    * @static
    * @param {HTMLElement} refEl: 参考对象
    * @param {string} sSelector: 过滤selector,
    * @returns {HTMLElement} : 返回element,如果获取不到,则反回null。
    * @example:
    var els=query(document,"li input.aaa");
    for(var i=0;i<els.length;i++ )els[i].style.backgroundColor='red';
    */
    one:
    function(refEl,sSelector){
    var els=Selector.query(refEl,sSelector);
    return els[0];
    }


    };

    window.__SltPsds
    =Selector._pseudos;//JK 2010-11-11:为提高效率
    /*

    retTrue 一个返回为true的函数
    */
    function retTrue(){
    return true;
    }

    /*
    arrFilter(arr,callback) : 对arr里的元素进行过滤
    */
    function arrFilter(arr,callback){
    var rlt=[],i=0;
    if(callback==retTrue){
    if(arr instanceof Array) return arr.slice(0);
    else{
    for(var len=arr.length;i<len;i++) {
    rlt[i]
    =arr[i];
    }
    }
    }
    else{
    for(var oI;oI=arr[i++];) {
    callback(oI)
    && rlt.push(oI);
    }
    }
    return rlt;
    };

    var elContains,//部分浏览器不支持contains(),例如FF
    getChildren,//部分浏览器不支持children,例如FF3.5-
    hasNativeQuery,//部分浏览器不支持原生querySelectorAll(),例如IE8-
    findId=function(id) {return document.getElementById(id);};

    (
    function(){
    var div=document.createElement('div');
    div.innerHTML
    ='<div class="aaa"></div>';
    hasNativeQuery
    =(div.querySelectorAll && div.querySelectorAll('.aaa').length==1);
    elContains
    =div.contains?
    function(pEl,el){ return pEl!=el && pEl.contains(el);}:
    function(pEl,el){ return (pEl.compareDocumentPosition(el) & 16);};
    getChildren
    =div.children?
    function(pEl){ return pEl.children;}:
    function(pEl){
    return arrFilter(pEl.childNodes,function(el){return el.tagName;});
    };
    })();


    function checkNth(el,nth,reverse){
    if(nth=='n') return true;
    if(typeof el =='number') var idx=el;
    else{
    var pEl=el.parentNode;
    if(pEl.__queryStamp!=queryStamp){
    var els=getChildren(pEl);
    for(var i=0,elI;elI=els[i++];){
    elI.__siblingIdx
    =i;
    };
    pEl.__queryStamp
    =queryStamp;
    pEl.__childrenNum
    =i-1;
    }
    if(reverse) idx=pEl.__childrenNum-el.__siblingIdx+1;
    else idx=el.__siblingIdx;
    alert([pEl.childNodes[
    0],pEl.childNodes[1],pEl.childNodes[2],pEl.childNodes[3],pEl.__childrenNum,el.__siblingIdx]);
    }
    switch (nth)
    {
    case 'even':
    case '2n':
    return idx%2==0;
    case 'odd':
    case '2n+1':
    return idx%2==1;
    default:
    if(!(/n/.test(nth))) return idx==nth;
    var arr=nth.replace(/(^|\D+)n/g,"$11n").split("n"),
    k
    =arr[0]|0,
    kn
    =idx-arr[1]|0;
    return k*kn>=0 && kn%k==0;
    }
    }
    /*
    * s2f(sSelector): 由一个selector得到一个过滤函数filter,这个selector里没有关系运算符(", >+~")
    */
    var filterCache={};
    function s2f(sSelector,isForArray){
    if(!isForArray && filterCache[sSelector]) return filterCache[sSelector];
    var pseudos=[],//伪类数组,每一个元素都是数组,依次为:伪类名/伪类值
    attrs=[],//属性数组,每一个元素都是数组,依次为:属性名/属性比较符/比较值
    s=trim(sSelector);
    s
    =s.replace(/\:([\w\-]+)(\(([^)]+)\))?/g,function(a,b,c,d,e){pseudos.push([b,d]);return "";});//伪类
    for(var i=0,shorthands=Selector._shorthands,sh;sh=shorthands[i];i++)
    s
    =s.replace(sh[0],sh[1]);
    //var reg=/\[\s*([\w\-]+)\s*([!~|^$*]?\=)?\s*(?:(["']?)([^\]'"]*)\3)?\s*\]/g; //属性选择表达式解析
    var reg=/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/g; //属性选择表达式解析,thanks JQuery
    s=s.replace(reg,function(a,b,c,d,e){attrs.push([b,c||"",e||""]);return "";});//普通写法[foo][foo=""][foo~=""]等
    if(!(/^\s*$/).test(s)) {
    throw "Unsupported Selector:\n"+sSelector+"\n-"+s;
    }

    var sFun=[];
    for(var i=0,attr;attr=attrs[i];i++){//属性过滤
    var attrGetter=Selector._attrGetters[attr[0]] || 'el.getAttribute("'+attr[0]+'")';
    sFun.push(Selector._operators[attr[
    1]].replace(/aa/g,attrGetter).replace(/vv/g,attr[2]));
    }
    for(var i=0,pI;pI=pseudos[i];i++) {//伪类过滤
    if(!Selector._pseudos[pI[0]]) throw "Unsupported Selector:\n"+pI[0]+"\n"+s;
    if(/^(nth-|not|contains)/.test(pI[0])){
    sFun.push(
    '__SltPsds["'+pI[0]+'"](el,"'+encode4Js(pI[1])+'")');
    }
    else{
    sFun.push(
    '__SltPsds["'+pI[0]+'"](el)');
    }
    }
    if (sFun.length)
    {
    if(isForArray){
    return new Function('els','var els2=[];for(var i=0,el;el=els[i++];){if('+sFun.join('&&')+') els2.push(el);} return els2;');
    }
    else{
    return filterCache[sSelector]=new Function('el','return '+sFun.join('&&')+';');
    }
    }
    else {
    if(isForArray){
    return function(els){return arrFilter(els,retTrue);}
    }
    else{
    return filterCache[sSelector]=retTrue;
    }

    }
    };

    /*
    * {int} xxxStamp: 全局变量查询标记
    */
    var queryStamp=0,
    relationStamp
    =0,
    querySimpleStamp
    =0;

    /*
    * nativeQuery(refEl,sSelector): 如果有原生的querySelectorAll,并且只是简单查询,则调用原生的query,否则返回null.
    * @param {Element} refEl 参考元素
    * @param {string} sSelector selector字符串
    * @returns
    */
    function nativeQuery(refEl,sSelector){
    if(hasNativeQuery && /^((^|,)\s*[.\w-][.\w\s\->+~]*)+$/.test(sSelector)) {
    //如果浏览器自带有querySelectorAll,并且本次query的是简单selector,则直接调用selector以加速
    //部分浏览器不支持以">~+"开始的关系运算符
    var arr=[],els=refEl.querySelectorAll(sSelector);
    for(var i=0,elI;elI=els[i++];) arr.push(elI);
    return arr;
    }
    return null;
    };

    /*
    * querySimple(pEl,sSelector): 得到pEl下的符合过滤条件的HTML Elements.
    * sSelector里没有","运算符
    * pEl是默认是document.body
    * @see: query。
    */
    function querySimple(pEl,sSelector){
    querySimpleStamp
    ++;
    /*
    为了提高查询速度,有以下优先原则:
    最优先:原生查询
    次优先:在' '、'>'关系符出现前,优先正向(从祖到孙)查询
    次优先:id查询
    次优先:只有一个关系符,则直接查询
    最原始策略,采用关系判断,即:从最底层向最上层连线,能连得成功,则满足条件
    */

    //最优先:原生查询
    var els=nativeQuery(pEl,sSelector);
    if(els) return els;//优先使用原生的


    var sltors=splitSelector(sSelector),
    pEls
    =[pEl],
    i,
    elI,
    pElI;

    var sltor0;
    //次优先:在' '、'>'关系符出现前,优先正向(从上到下)查询
    while(sltor0=sltors[0]){
    if(!pEls.length) return [];
    var relation=sltor0[0];
    els
    =[];
    if(relation=='+'){//第一个弟弟
    filter=s2f(sltor0[1]);
    for(i=0;elI=pEls[i++];){
    while(elI=elI.nextSibling){
    if(elI.tagName){
    if(filter(elI)) els.push(elI);
    break;
    }
    }
    }
    pEls
    =els;
    sltors.splice(
    0,1);
    }
    else if(relation=='~'){//所有的弟弟
    filter=s2f(sltor0[1]);
    for(i=0;elI=pEls[i++];){
    if(i>1 && elI.parentNode==pEls[i-2].parentNode) continue;//除重:如果已经query过兄长,则不必query弟弟
    while(elI=elI.nextSibling){
    if(elI.tagName){
    if(filter(elI)) els.push(elI);
    }
    }
    }
    pEls
    =els;
    sltors.splice(
    0,1);
    }
    else{
    break;
    }
    }
    var sltorsLen=sltors.length;
    if(!sltorsLen || !pEls.length) return pEls;

    //次优先:idIdx查询
    for(var idIdx=0,id;sltor=sltors[idIdx];idIdx++){
    if((/^[.\w-]*#([\w-]+)/i).test(sltor[1])){
    id
    =RegExp.$1;
    sltor[
    1]=sltor[1].replace('#'+id,'');
    break;
    }
    }
    if(idIdx<sltorsLen){//存在id
    var idEl=findId(id);
    if(!idEl) return [];
    for(i=0,pElI;pElI=pEls[i++];){
    if(elContains(pElI,idEl)) {
    els
    =filterByRelation(pEl,[idEl],sltors.slice(0,idIdx+1));
    if(!els.length || idIdx==sltorsLen-1) return els;
    return querySimple(idEl,sltors.slice(idIdx+1).join(',').replace(/,/g,' '));
    }
    }
    return [];
    }

    //---------------
    var getChildrenFun=function(pEl){return pEl.getElementsByTagName(tagName);},
    tagName
    ='*',
    className
    ='';
    sSelector
    =sltors[sltorsLen-1][1];
    sSelector
    =sSelector.replace(/^[\w\-]+/,function(a){tagName=a;return ""});
    if(hasNativeQuery){
    sSelector
    =sSelector.replace(/^[\w\*]*\.([\w\-]+)/,function(a,b){className=b;return ""});
    }
    if(className){
    getChildrenFun
    =function(pEl){return pEl.querySelectorAll(tagName+'.'+className);};
    }

    //次优先:只剩一个'>'或' '关系符(结合前面的代码,这时不可能出现还只剩'+'或'~'关系符)
    if(sltorsLen==1){
    if(sltors[0][0]=='>') {
    getChildrenFun
    =getChildren;
    var filter=s2f(sltors[0][1],true);
    }
    else{
    filter
    =s2f(sSelector,true);
    }
    els
    =[];
    for(i=0;pElI=pEls[i++];){
    els
    =els.concat(filter(getChildrenFun(pElI)));
    }
    return els;
    }


    //走第一个关系符是'>'或' '的万能方案
    sltors[sltors.length-1][1] = sSelector;
    els
    =[];
    for(i=0;pElI=pEls[i++];){
    els
    =els.concat(filterByRelation(pElI,getChildrenFun(pElI),sltors));
    }
    return els;
    };


    function splitSelector(sSelector){
    var sltors=[];
    var reg=/(^|\s*[>+~ ]\s*)(([\w\-\:.#*]+|\([^\)]*\)|\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\6|)\s*\])+)(?=($|\s*[>+~ ]\s*))/g;
    var s=trim(sSelector).replace(reg,function(a,b,c,d){sltors.push([trim(b),c]);return "";});
    if(!(/^\s*$/).test(s)) {
    throw "Unsupported Selector:\n"+sSelector+"\n--"+s;
    }
    return sltors;
    }

    /*
    判断一个长辈与子孙节点是否满足关系要求。----特别说明:这里的第一个关系只能是父子关系,或祖孙关系;
    */

    function filterByRelation(pEl,els,sltors){
    relationStamp
    ++;
    var sltor=sltors[0],
    len
    =sltors.length,
    needNotTopJudge
    =!sltor[0],
    filters
    =[],
    relations
    =[],
    needNext
    =[],
    relationsStr
    ='';

    for(var i=0;i<len;i++){
    sltor
    =sltors[i];
    filters[i]
    =s2f(sltor[1],i==len-1);//过滤
    relations[i]=Selector._relations[sltor[0]];//寻亲函数
    if(sltor[0]=='' || sltor[0]=='~') needNext[i]=true;//是否递归寻亲
    relationsStr+=sltor[0]|' ';
    }
    els
    =filters[len-1](els);//自身过滤
    if(len==1) return els;
    if(/[+>~] |[+]~/.test(relationsStr)){//需要回溯
    //alert(1); //用到这个分支的可能性很注。放弃效率的追求。
    function chkRelation(el){//关系人过滤
    var parties=[],//中间关系人
    j=len-1,
    party
    =parties[j]=el;
    for(;j>-1;j--){
    if(j>0){//非最后一步的情况
    party=relations[j](party,filters[j-1],pEl);
    }
    else if(needNotTopJudge || party.parentNode==pEl){//最后一步通过判断
    return true;
    }
    else {//最后一步未通过判断
    party=null;
    }
    while(!party){//回溯
    if(++j==len) { //cache不通过
    return false;
    }
    if(needNext[j]) {
    party
    =parties[j-1];
    j
    ++;
    }
    }
    parties[j
    -1]=party;
    }
    };
    return arrFilter(els,chkRelation);
    }
    else{//不需回溯
    var els2=[];
    for(var i=0,el,elI; el=elI=els[i++] ; ) {
    for(var j=len-1;j>0;j--){
    if(!(el=relations[j](el,filters[j-1],pEl))) {
    break;
    }
    }
    if(el && (needNotTopJudge || el.parentNode==pEl)) els2.push(elI);
    }
    return els2;
    }

    }

    QW.Selector
    =Selector;
    })();
  • 相关阅读:
    postgres--流复制
    postgres--wal
    postgres--vacuum
    postgres10配置huge_pages
    Postgres间隔大量写IO的解决办法
    PostgreSQL配置文件--其他
    PostgreSQL配置文件--AUTOVACUUM参数
    PostgreSQL配置文件--实时统计
    PostgreSQL配置文件--日志和错误
    PostgreSQL配置文件--QUERY TUNING
  • 原文地址:https://www.cnblogs.com/jkisjk/p/qwrap_selector_methods.html
Copyright © 2011-2022 走看看