小弟菜菜滴,看了PRO和JQ的选择器,看的晕晕的,不明白其中原理,有哪个能写个裸体版的选择器,让小虾们看看原理

解决方案 »

  1.   

    没什么吧就是具备一些简单算法的dom节点选择而易啊。
      

  2.   

    <pre>
    /** 
     * querySelector(sSelector,[pEl]): 得到pEl下的符合过滤条件的HTML Elements. 
     * example: var els=IUIDom.querySelector("li input.aaa");els.forEach(function(a){a.style.backgroundColor='red';}); 
     * @param {string} sSelector: 过滤selector, 目前支持的运算符:
    * √
    E √
    .class  √
    #id √
    E F √
    E > √
    E + F √
    E[attr] √
    E[attr=val] √
    E[attr~=val] √
    E[attr|=val] √
    :first-child √
    :link 
    :visited 
    :lang()    
    :before
    ::before
    :after
    ::after
    :first-letter
    ::first-letter
    :first-line
    ::first-line
    --------------------------
    下面的选择器属于CSS3 (上面的在以前的版本中)
    E[attr^=val] √
    E[attr$=val] √
    E[attr*=val] √
    E ~ F √
    :root 
    :last-child √
    :only-child √
    :nth-child() √
    :nth-last-child() √
    :first-of-type √
    :last-of-type √
    :only-of-type √
    :nth-of-type() √
    :nth-last-of-type() √
    :empty √
    :not() √
    :target 
    :enabled √
    :disabled √
    :checked √
    --------------------------
    其它
    :parent √
    --------------------------
    示例:
    "ul li" 
    ">ul li"
    "ul li:first-child"
    "li:nth-child(2n)"----nth支持参数如:'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
     * @param {HTMLElement} pEl: 容器对象 
     * @returns {array} : 返回elements数组。 
     */
     </pre><script>
    /**
     * @IUI
     * @author: JK([email protected])
     * @create-date : 2008-09-18
     *///{prepare------------------------------------
    String.prototype.trim=function(){
    return this.replace(/^[\s\xa0\u3000]+|[\u3000\xa0\s]+$/g, "")
    }; if(!Array.prototype.forEach){
    Array.prototype.forEach=function(callback,pThis){
    for (var i =0,len=this.length;i<len;i++) callback.call(pThis,this[i],i,this);
    };
    }
    //------------------------------------prepare}/** 
     * Dom: IUI.Dom
     * @version: 0.0.1
     */
    (function(){
    window.IUIDom=
    {
    VERSION:"0.0.1", /** 
     * selector2Filter(sSelector): 把一个selector字符串转化成一个过滤函数.
     * example: var fun=IUIDom.selector2Filter("input.aaa");alert(fun);
     * @param {string} sSelector: 过滤selector,目前只支持以下几种选择符:"逗号-或" "空格-与" "点-className" "abc-tagName" "#-id".
     * @returns {function} : 返回过滤函数。
     */
    selector2Filter:function(sSelector){
    return s2f(sSelector);
    },
    /** 
     * querySelector(sSelector,[pEl]): 得到pEl下的符合过滤条件的HTML Elements. pEl是默认是document.
     * example: var els=IUIDom.querySelector("li input.aaa");els.forEach(function(a){a.style.backgroundColor='red';});
     * @param {string} sSelector: 过滤selector,目前只支持以下几种选择符:"逗号-或" "空格-与" "点-className" "abc-tagName" "#-id".
     * @param {HTMLElement} pEl: 容器对象
     * @returns {array} : 返回elements数组。
     */
    querySelector:function(sSelector,pEl){
    if(typeof(pEl)=="string" && !(pEl=$(pEl))) return [];
    pEl=pEl||document;
    var groups=sSelector.trim().split(",");
    var els=querySimpleSelector(groups[0],pEl);
    for(var i=1;i<groups.length;i++){
    var els2=querySimpleSelector(groups[i],pEl);
    els=els.concatUnique(els2);
    }
    return els;
    }
    };
    /**
    fasterFilter(arr,callback) : 对arr里的元素进行过滤,fun(a)快于fun.call(thisP)
    @see IUI.filter(arr,callback) 
    */
    function fasterFilter(arr,callback){
    var rlt=[],n=0;
    for(var i=0,len=arr.length;i<len;i++) {
    var el=arr[i];
    if(callback(el)) rlt[n++]=el;
    }
    return rlt;
    };if(document.createElement("a").contains){
    var fasterContains=function(pEl,el){ return pEl.contains(el);};
    }
    else{
    var fasterContains=function(pEl,el){ return (pEl.compareDocumentPosition(el) & 16);};
    }/**
     * nth(sN): 返回一个判断函数,来判断一个数是否满足某表达式。
     * @param { string } sN: 表达式,如:'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
     * @return { function } function(i){return i满足sN}: 返回判断函数。
     */
    function nth(sN){
    if(sN=="even") return function(i){return i%2==0;};
    if(sN=="odd") return function(i){return i%2!=0;};
    sN=sN.replace(/(^|\D+)n/g,"$11n");
    if(!(/n/.test(sN))) {
    return function(i){return i==sN;}
    }
    else{
    var arr=sN.split("n");
    var a=parseInt(arr[0]),b=parseInt(arr[1]||"0");
    return function(i){var n=(i-b)/a; return n>=0 && parseInt(n)==n;};
    }
    }/**
     * getNth(el,reverse): 得到一个元素的nth值。
     * @param { element } el: HTML Element
     * @param { boolean } : 是否反向算--如果为真,相当于nth-last
     * @return { int } : 返回nth值
     */
    function getNth(el,reverse){
    var pEl=el.parentNode;
    if(pEl.__lastQueryDate!=_queryDate){
    var els=pEl.childNodes,idx=0;
    for(var i=0,len=els.length;i<len;i++){
    var elI=els[i];
    if("tagName" in elI) elI.__nodeIndex=++idx;
    };
    pEl.__lastQueryDate=_queryDate;
    pEl.__childNodesLength=idx;
    }
    if(reverse) return pEl.__childNodesLength-el.__nodeIndex+1;
    else return el.__nodeIndex;
    }/**
     * CSS selector属性运算符---(为了提高速度,以下表达式的结果如果返回true,则表示不满足条件)
     */
    var Ops={
    '': '!v1',//isTrue|hasValue
    '=': 'v1!="v2"',//equal
    '!=': 'v1=="v2"', //unequal
    '~=': '!v1||(" "+v1+" ").indexOf(" v2 ")<0',//onePart
    '|=': '!v1||(v1+"-").indexOf("v2-")!=0', //firstPart
    '^=': '!v1||v1.indexOf("v2")!=0', // beginWith
    '$=': '!v1||v1.lastIndexOf("v2")!=v1.length-"v2".length', // endWith
    '*=': '!v1||v1.indexOf("v2")<0' //contains
    };
    /**
     * CSS 伪类逻辑
     */
    var Pseudos={
    "first-child":function(a){return (a.parentNode.getElementsByTagName("*")[0]==a);},
    "last-child":function(a){var oLast=a.parentNode.lastChild; return oLast==a || (!oLast.tagName && oLast.previousSibling==a);},
    "only-child":function(a){var els=a.parentNode.childNodes; return els.length<3 && fasterFilter(els,function(b){return "tagName" in b;}).length==1 ;},
    "nth-child":function(a,iFlt){return iFlt(getNth(a,false)); },
    "nth-last-child":function(a,iFlt){return iFlt(getNth(a,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,iFlt){var idx=1;var el=a;while(el=el.previousSibling) {if(el.tagName==a.tagName) idx++;} return iFlt(idx); },
    "nth-last-of-type":function(a,iFlt){var idx=1;var el=a;while(el=el.nextSibling) {if(el.tagName==a.tagName) idx++;} return iFlt(idx); },
    "empty":function(a){ return !a.firstChild; },
    "parent":function(a){ return !!a.firstChild; },
    "not":function(a,sFlt){ return !sFlt(a); },
    "enabled":function(a){ return !a.disabled; },
    "disabled":function(a){ return a.disabled; },
    "checked":function(a){ return a.checked; }
    };/**
     * 常用的Element属性
     */
    var ElAttrs={
    'class': 'className;', 
    'for': 'htmlFor;'
    };
    "name,id,className,value,selected,checked,disabled,type,tagName,readOnly".split(",").forEach(function (a){ElAttrs[a]=a;});
    /**
     * CSS selector关系运算符
     */
    var Relations={
    //子子孙孙
    " ":function(el,filter,tagName){
    var els=el.getElementsByTagName(tagName||"*");
    return fasterFilter(els,filter);
    },
    //儿子们
    ">":function(el,filter){
    var nodes=el.childNodes;
    var els=[];
    for(var i=0,len=nodes.length;i<len;i++){
    var elI=nodes[i];
    if(("tagName" in elI) && filter(elI)) els.push(elI);
    }
    return els;
    },
    //第一个弟弟
    "+":function(el,filter){
    var elI=el;
    while(elI=elI.nextSibling){
    if("tagName" in elI){
    if(filter(elI)) return [elI];
    else return [];
    }
    }
    return [];
    },
    //弟弟们
    "~":function(el,filter){
    var arr=[];
    var elI=el;
    while(elI=elI.nextSibling){
    if(elI.tagName && filter(elI)) arr.push(elI);
    }
    return arr;
    }
    }
      

  3.   

    /** 
     * s2f(sSelector): 由一个selector得到一个过滤函数filter,这个selector里没有关系运算符(", >+~")
     */
    function s2f(sSelector){
    var attrs=[];
    eval("var flts=[];");//防止压缩被更名
    var s=sSelector.trim();
    s=s.replace(/\:([\w\-]+)(\(([^)]+)\))?/g,function(a,b,c,d,e){flts.push([b,d]);return "";});//伪类
    s=s.replace(/^\*/g,'[tagName]');//任意tagName缩略写法
    s=s.replace(/^([\w\-]+)/g,function(a,b){return '[tagName="'+b.toUpperCase()+'"]';});//tagName缩略写法
    s=s.replace(/\.([\w\-]+)/g,'[className~="$1"]');//className缩略写法
    s=s.replace(/\#([\w\-]+)/g,'[id="$1"]');//id缩略写法
    var reg=/\[\s*([\w\-]+)\s*([!~|^$*]?\=)?\s*(?:"([^\]]*)")?\s*\]/g;
    s=s.replace(reg,function(a,b,c,d){attrs.push([b,c||"",d||""]);return "";});//普通写法[foo][foo=""][foo~=""]等
    if(!(/^\s*$/).test(s)) {var ex="Unsupported by IUI Selector:\n"+sSelector+"\n-"+s; alert(ex);throw ex;}
    var sFun=[];
    for(var i=0;i<attrs.length;i++){//属性过滤
    var attr=attrs[i];
    sFun.push('var v1=a.'+(ElAttrs[attr[0]]||(attr[0]+'||a.getAttribute("'+attr[0]+'")'))+";",
    'if('+Ops[attr[1]].replace(/v2/g,attr[2])+') return false;');
    }
    for(var i=0;i<flts.length;i++) {//伪类过滤
    var fun=Pseudos[flts[i][0]];
    if(!fun) {var ex="Unsupported by IUI Selector:\n"+flts[0]+"\n"+s; alert(ex);throw ex;}
    flts[i][2]=fun;
    eval('var flt'+i+'=flts['+i+'][2];');//降低层次深度,以提高效率
    if(flts[i][0].indexOf("nth-")==0){
    flts[i][3]=nth(flts[i][1]);
    }
    else if(flts[i][0]=="not"){
    flts[i][3]=s2f(flts[i][1]);
    }
    if(flts[i][3]){
    eval('var subFlt'+i+'=flts['+i+'][3];');
    sFun.push('if (!flt'+i+'(a,subFlt'+i+')) return false;');
    }
    else{
    sFun.push('if (!flt'+i+'(a)) return false;');
    }
    }
    sFun.push("return true;"); eval("var attrFlt= function(a){"+sFun.join("\n")+"}");
    return attrFlt;
    };/** 
    * {date} _queryDate: 全局变量,标记下最后一次querySelector的时间
     */
    var _queryDate=1;
    /** 
     * querySimpleSelector(sSelector,pEl): 得到pEl下的符合过滤条件的HTML Elements. 
     * sSelector里没有","运算符
     * pEl是默认是document.body 
     * @see: querySelector。
     */
    function querySimpleSelector(sSelector,pEl){
    _queryDate=new Date()*1;
    var sltors=[];
    var reg=/(^|\s*[>+~ ]\s*)(([\w\-\:.#*]+|\([^\)]*\)|\[[^\]]*\])+)(?=($|\s*[>+~ ]\s*))/g;
    var s=sSelector.trim().replace(reg,function(a,b,c,d){sltors.push([b,c]);return "";});
    if(!(/^\s*$/).test(s)) {var ex="Unsupported by IUI Selector:\n"+sSelector+"\n--"+s; alert(ex);throw ex;}
    var els=[pEl];
    var pOp=null;//前一个关系运算符
    for(var i=0;i<sltors.length;i++){
    var els2=[];
    var sltor=sltors[i];
    var op=sltor[0].trim() || " ";
    if (op==" " && pOp==" ")//除冗以提高效率----某些特殊情况(如:为" div~div div"第二个空格除冗),除冗会不够彻底。为了保证绝大多数用法的效率,只能放弃理论追求了
    {
    for(var j=1;j<els.length;j++)
    {
    if(fasterContains(els[j-1],els[j])){
    els.splice(j,1);
    j--;
    }
    }
    }
    var tagName="*";
    if(op==" ") {
    sltor[1]=sltor[1].replace(/^[\w\-]+/,function(a){tagName=a;return ""});
    }
    var filter=s2f(sltor[1]);
    var relation=Relations[op];
    if(op=="~"){
    for(var j=0;j<els.length;j++){
    var elsj=relation(els[j],filter,tagName);
    els2=els2.length && els2.concatUnique(elsj) || elsj; //需要除重
    }
    }
    else{
    for(var j=0;j<els.length;j++){
    var elsj=relation(els[j],filter,tagName);
    els2=els2.concat(elsj);//不除重
    }
    }
    els=els2;
    pOp=op;
    }
    return els;
    };
    })();
    </script>更多内容,可以参考:
    http://download.csdn.net/source/997377
      

  4.   

    YUI的selector是从下往上找的,
    我当时写的时候,也是从下往上找,后来还是改成从上往下找,导致有时候除重不够彻底。不足中