WEB开发网
开发学院网页设计JavaScript jQuery.API源码深入剖析以及应用实现(4) - 选择器... 阅读

jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)

 2010-09-14 13:39:24 来源:WEB开发网   
核心提示:这篇继上篇的 jQuery.API源码深入剖析以及应用实现(3) - 选择器篇(上) 之后继续介绍选择器的其它原理,包括内容,jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下),可见性,属性,【 :selected 】它们匹配的正则表达式为:PSEUDO:/:((?:[wu00c0-uFFFF_-]

这篇继上篇的 jQuery.API源码深入剖析以及应用实现(3) - 选择器篇(上) 之后继续介绍选择器的其它原理,包括内容,可见性,属性,子元素,表单,表单对象属性等等原理。

jQuery选择器的图示包括:

jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)

一、内容

1. 【 :contains(text) 】

匹配包含给定文本的元素。

例子

HTML代码jQuery代码结果
<div>John Resig</div>
<div>George Martin</div>
<div>Malcom John Sinclair</div>
<div>J. Ohn </div>
$("div:contains('John')")[ <div>John Resig</div>, <div>Malcom John Sinclair</div> ]

首先我们先找到它的一个正则表达式

PSEUDO:/:((?:[wu00c0-uFFFF_-]|.)+)(?:((['"]*)((?:([^)]+)|[^2()]*)+)2))?/

然后找到它的核心代码:

filter:{
  PSEUDO:function(elem,match,i,array){
    varname=match[1],filter=Expr.filters[name];
    if(filter){
      returnfilter(elem,i,match,array);
    }elseif(name==="contains"){
      //textContext在FF下和innerText在IE下的属性是等效的,match[3]得到的是contains紧跟在后面包含的字符串,当elem元素的文本内容包含contains包含的关键字时,返回true
      return(elem.textContent||elem.innerText||"").indexOf(match[3])>=0;
    }elseif(name==="not"){
      varnot=match[3];
      for(vari=0,l=not.length;i<l;i++){
        if(not[i]===elem){
          returnfalse;
        }
      }
      returntrue;
    }
  }
}

关键在于 (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; 的布尔值判断,当返回真时,elem元素为匹配的元素。

2. 【 :empty 】,【 :has(selector) 】,【 :parent 】

:empty匹配所有不包含子元素或者文本的空元素。

:has(selector) 匹配含有选择器所匹配的元素的元素。

:parent匹配含有子元素或者文本的元素。

例子

HTML代码jQuery代码结果
<table>
 <tr><td>Value 1</td><td></td></tr>
 <tr><td>Value 2</td><td></td></tr>
</table>
$("td:empty")[ <td></td>, <td></td> ]
<div><p>Hello</p></div>
<div>Hello again!</div>
$("div:has(p)").addClass("test");[ <div class="test"><p>Hello</p></div> ]
<table>
 <tr><td>Value 1</td><td></td></tr>
 <tr><td>Value 2</td><td></td></tr>
</table>
$("td:parent")[ <td>Value 1</td>, <td>Value 1</td> ]

同样它匹配正则表达式PSEUDO。

找到它们的核心代码:

filters:{
  parent:function(elem){
    return!!elem.firstChild;
  },
  empty:function(elem){
    return!elem.firstChild;
  },
  has:function(elem,i,match){
    return!!Sizzle(match[3],elem).length;
  }
}

其中当!elem.firstChild即elem元素不包含子节点或者文本元素时,empty返回真;

当!!elem.firstChild即elem元素包含子节点或者文本元素时,parent返回真;

has中,match[3]为has紧跟在后面含有的元素,如p元素,!!Sizzle( match[3], elem ).length 得到 match[3]元素中包含在elem元素中的个数,如果个数 > 1,has返回真。

二、可见性

1. 【 :hidden 】和【 :visible 】

: hidden匹配所有的不可见元素,input 元素的 type 属性为 "hidden" 的话也会被匹配到。

:visible匹配所有的可见元素。

我们只需要看它的核心代码为:

jQuery.expr=Sizzle.selectors;
//…
Sizzle.selectors.filters.hidden=function(elem){
  return"hidden"===elem.type||
    jQuery.css(elem,"display")==="none"||
    jQuery.css(elem,"visibility")==="hidden";
};
Sizzle.selectors.filters.visible=function(elem){
  return"hidden"!==elem.type&&
    jQuery.css(elem,"display")!=="none"&&
    jQuery.css(elem,"visibility")!=="hidden";
};

当elem元素的CSS属性display为”none”,或者visibility为”hidden”时,返回真;

当elem元素的CSS属性display不为”none”,并且visibility不为”hidden”时,返回真。

通过布尔值来判断元素是否显示。

三、属性

1. [ attribute ],[ attribute=value ],[ attribute!=value ],[ attribute^=value ],[ attribute$=value ],[ attribute*=value ]

属性匹配的正则表达式为:

ATTR:/[s*((?:[wu00c0-uFFFF_-]|.)+)s*(?:(S?=)s*(['"]*)(.*?)3|)s*]/

通过Sizzle.filter方法,得到ATTR的正则匹配,然后调用Expr.filter[ “ATTR” ],具体实现为:

filters:{
  //如$("input[name^='news']")【<inputname="newsletter"/>】
  ATTR:function(elem,match){
    varresult=Expr.attrHandle[match[1]]?Expr.attrHandle[match[1]](elem):elem[match[1]]||elem.getAttribute(match[1]),value=result+"",type=match[2],check=match[4];
    returnresult==null?
      type==="!=":
      type==="="?
      value===check:
      type==="*="?
      value.indexOf(check)>=0:
      type==="~="?
      (""+value+"").indexOf(check)>=0:
      !match[4]?
      result:
      type==="!="?
      value!=check:
      type==="^="?
      value.indexOf(check)===0:
      type==="$="?
      value.substr(value.length-check.length)===check:
      type==="|="?
      value===check||value.substr(0,check.length+1)===check+"-":
      false;
  }
}

其中value相当于“newsletter”,check相当于“new”;

可以看出“!=”和“=”判断value === check; 的布尔值,即value是否等于check;

“^=”取得value.index(check) === 0; 的布尔值,即check的字符串是否在value的开头;

“$=”取得value.substr(value.length - check.length) === check; 的布尔值,即check的字符串是否在value的末尾;

“*=”取得value.index(check) >= 0; 的布尔值,即value包含check字符串为真;

四、子元素

1. 【 :nth-child(index/even/odd/equation) 】,【 :first-child 】,【 :last-child 】,【 :only-child 】

:nth-child(index/even/odd/equation) 匹配其父元素下的第N个子或奇偶元素。

:first-child 匹配第一个子元素。

:last-child 匹配最后一个子元素。

:only-child 如果某个元素是父元素中唯一的子元素,那将会被匹配。

它匹配的正则表达式为:

CHILD:/:(only|nth|last|first)-child(?:((even|odd|[dn+-]*)))?/

通过Sizzle.filter方法,得到CHILD的正则匹配,然后调用Expr.filter[ “CHILD” ],具体实现为:

filter:{
    CHILD:function(elem,match){
      vartype=match[1],parent=elem.parentNode;
      vardoneName=match[0];
      if(parent&&(!parent[doneName]||!elem.nodeIndex)){
        varcount=1;
        for(varnode=parent.firstChild;node;node=node.nextSibling){
          if(node.nodeType==1){
            node.nodeIndex=count++;
          }
        }
        parent[doneName]=count-1;
      }
      if(type=="first"){
        returnelem.nodeIndex==1;
      }elseif(type=="last"){
        returnelem.nodeIndex==parent[doneName];
      }elseif(type=="only"){
        returnparent[doneName]==1;
      }elseif(type=="nth"){
        varadd=false,first=match[2],last=match[3];
        if(first==1&&last==0){
          returntrue;
        }
        if(first==0){
          //形如$("ulli:nth-child(2)")
          if(elem.nodeIndex==last){
            add=true;
          }
        }
        //形如$("ulli:nth-child(even)"),$("ulli:nth-child(odd)"),$("ulli::nth-child(3n+1)")
        elseif((elem.nodeIndex-last)%first==0&&(elem.nodeIndex-last)/first>=0){
          add=true;
        }
        returnadd;
      }
    }
}

其中type为first时,elem.nodeIndex == 1; 当elem元素为第一个节点时,返回真;

type为last时,elem.nodeIndex == parent[ doneName ]; 当elem元素为它的父节点的最后一个子节点时,返回真;

type为only时,parent[ doneName ] == 1; 当elem元素的父节点只有一个子节点时,返回真;

type为nth时,各种情况已经在代码中标注。

五、表单

1. 【 :input 】,【 :text 】,【 :password 】,【 :radio 】,【 :checkbox 】,【 :submit 】,【 :image 】,【 :reset 】,【 :button 】,【 :file 】,【 :hidden 】

它们匹配的正则表达式为:

PSEUDO:/:((?:[wu00c0-uFFFF_-]|.)+)(?:((['"]*)((?:([^)]+)|[^2()]*)+)2))?/

找到它们的核心代码:

  filters:{
    text:function(elem){
      return"text"===elem.type;
    },
    radio:function(elem){
      return"radio"===elem.type;
    },
    checkbox:function(elem){
      return"checkbox"===elem.type;
    },
    file:function(elem){
      return"file"===elem.type;
    },
    password:function(elem){
      return"password"===elem.type;
    },
    submit:function(elem){
      return"submit"===elem.type;
    },
    image:function(elem){
      return"image"===elem.type;
    },
    reset:function(elem){
      return"reset"===elem.type;
    },
    button:function(elem){
      return"button"===elem.type||elem.nodeName.toUpperCase()==="BUTTON";
    },
    input:function(elem){
      return/input|select|textarea|button/i.test(elem.nodeName);
    }
  }

可以看出elem.type得到元素的type属性,当元素type属性等于相应的值时,返回相应的布尔值。

如果为真,最后返回匹配的jQuery对象。

六、表单对象属性

1. 【 : enabled 】,【 : disabled 】,【 : checked 】,【 :selected 】

它们匹配的正则表达式为:

PSEUDO:/:((?:[wu00c0-uFFFF_-]|.)+)(?:((['"]*)((?:([^)]+)|[^2()]*)+)2))?/

找到它们的核心代码:

  filters:{
    enabled:function(elem){
      returnelem.disabled===false&&elem.type!=="hidden";
    },
    disabled:function(elem){
      returnelem.disabled===true;
    },
    checked:function(elem){
      returnelem.checked===true;
    },
    selected:function(elem){
      //Accessingthispropertymakesselected-by-default
      //optionsinSafariworkproperly
      elem.parentNode.selectedIndex;
      returnelem.selected===true;
    }
  }

其中,enabled对应elem的disabled属性为false并且elem的type属性为hidden;

disabled对应elem的disabled属性为true;

checked对应elem的checked属性为true;

selected对应elem的selected属性为true;

jQuery的选择器的原理至此已经全部介绍完了,通过选择器认识到了通过Expr.filters达到了过滤的目的。

下篇我将介绍jQuery中的属性的原理。

系列文章:

jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇

jQuery.API源码深入剖析以及应用实现(2) - jQuery对象访问和数据缓存

jQuery.API源码深入剖析以及应用实现(3) - 选择器篇(上)

jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)

Tags:jQuery API 源码

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接