zoukankan      html  css  js  c++  java
  • jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)

    继续介绍选择器的其它原理,包括内容,可见性,属性,子元素,表单,表单对象属性等等原理。

    jQuery选择器的图示包括:


    一、内容

    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: /:((?:["w"u00c0-"uFFFF_-]|"".)+)(?:"((['"]*)((?:"([^")]+")|[^"2"(")]*)+)"2"))?/

    然后找到它的核心代码:

    filter: {
        PSEUDO: 
    function(elem, match, i, array){
            
    var name = match[1], filter = Expr.filters[ name ];

            
    if ( filter ) {
                
    return filter( elem, i, match, array );
            } 
    else if ( name === "contains" ) { 
                
    // textContext在FF下和innerText在IE下的属性是等效的,match[3]得到的是contains紧跟在后面包含的字符串,当elem元素的文本内容包含contains包含的关键字时,返回true
                return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
            } 
    else if ( name === "not" ) {
                
    var not = match[3];

                
    for ( var i = 0, l = not.length; i < l; i++ ) {
                    
    if ( not[i] === elem ) {
                        
    return false;
                    }
                }

                
    return true;
            }
        }
    }

    关键在于 (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*((?:["w"u00c0-"uFFFF_-]|"".)+)"s*(?:("S?=)"s*(['"]*)(.*?)"3|)"s*"]/

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

    filters: {
        
    // 如 $("input[name^='news']")【<input name="newsletter" />】
        ATTR: function(elem, match){
            
    var result = Expr.attrHandle[ match[1] ] ? Expr.attrHandle[ match[1] ]( elem ) : elem[ match[1] ] || elem.getAttribute( match[1] ), value = result + "", type = match[2], check = match[4];
            
    return result == 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){
                
    var type = match[1], parent = elem.parentNode;

                
    var doneName = match[0];

                
    if ( parent && (!parent[ doneName ] || !elem.nodeIndex) ) {
                    
    var count = 1;

                    
    for ( var node = parent.firstChild; node; node = node.nextSibling ) {
                        
    if ( node.nodeType == 1 ) {
                            node.nodeIndex 
    = count++;
                        }
                    }

                    parent[ doneName ] 
    = count - 1;
                }

                
    if ( type == "first" ) {
                    
    return elem.nodeIndex == 1;
                } 
    else if ( type == "last" ) {
                    
    return elem.nodeIndex == parent[ doneName ];
                } 
    else if ( type == "only" ) {
                    
    return parent[ doneName ] == 1;
                } 
    else if ( type == "nth" ) {
                    
    var add = false, first = match[2], last = match[3];

                    
    if ( first == 1 && last == 0 ) {
                        
    return true;
                    }

                    
    if ( first == 0 ) {
                        
    // 形如 $("ul li:nth-child(2)")
                        if ( elem.nodeIndex == last ) {
                            add 
    = true;
                        }
                    } 
                    
    // 形如 $("ul li:nth-child(even)"), $("ul li:nth-child(odd)"),$("ul li::nth-child(3n+1)")
                    else if ( (elem.nodeIndex - last) % first == 0 && (elem.nodeIndex - last) / first >= 0 ) {
                        add 
    = true;
                    }

                    
    return add;
                }
            }
    }

    其中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: /:((?:["w"u00c0-"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: /:((?:["w"u00c0-"uFFFF_-]|"".)+)(?:"((['"]*)((?:"([^")]+")|[^"2"(")]*)+)"2"))?/

    找到它们的核心代码:

        filters: {
            enabled: 
    function(elem){
                
    return elem.disabled === false && elem.type !== "hidden";
            },
            disabled: 
    function(elem){
                
    return elem.disabled === true;
            },
            checked: 
    function(elem){
                
    return elem.checked === true;
            },
            selected: 
    function(elem){
                
    // Accessing this property makes selected-by-default
                // options in Safari work properly
                elem.parentNode.selectedIndex;
                
    return elem.selected === true;
            }
        }

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


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

  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/lzhdim/p/1395328.html
Copyright © 2011-2022 走看看