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

简介: 继续介绍选择器的其它原理,包括内容,可见性,属性,子元素,表单,表单对象属性等等原理。 jQuery选择器的图示包括: 一、内容 1. 【 :contains(text) 】 匹配包含给定文本的元素。

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

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 ;
                    }
                } 
                
//  形如 ("ulli:nthchild(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达到了过滤的目的。

目录
打赏
0
0
0
0
16
分享
相关文章
小红书笔记详情 API 接口的开发、应用与收益
小红书(RED)作为国内领先的生活方式分享平台,汇聚了大量用户生成内容(UGC),尤其是“种草”笔记。小红书笔记详情API接口为开发者提供了获取笔记详细信息的强大工具,包括标题、内容、图片、点赞数等。通过注册开放平台账号、申请API权限并调用接口,开发者可以构建内容分析工具、笔记推荐系统、数据爬虫等应用,提升用户体验和运营效率,创造新的商业模式。本文详细介绍API的开发流程、应用场景及潜在收益,并附上Python代码示例。
202 61
单页图床HTML源码+本地API接口图床系统源码
图床系统是一种用于存储和管理图片文件的在线服务。它允许用户上传图片文件,并生成相应的图片链接,从而方便用户在网页、社交媒体或其他平台上分享图片。
26 2
单页图床HTML源码+本地API接口图床系统源码
1688 快递费用 API 接口的技术剖析与应用
1688快递费用API接口为企业和开发者提供自动化、高效化的快递费用查询服务,打破人工查询的繁琐局面。通过输入寄件与收件地址、商品重量、体积及选择快递公司等信息,接口精准计算费用并返回结果,支持中通、圆通等主流快递。输出内容包括快递费用、预估时效及附加费说明,助力电商精细化运营。Python示例代码展示了如何使用requests库发起POST请求并解析响应数据,实现费用查询自动化。
28 10
【03】支付宝支付商户申请下户到配置完整流程-对签约申请已通过商户进行开通API支付-创建应用-申请支付宝公钥-应用公钥-支付宝密钥-配合支付宝官方证书生成工具+配置完整流程-优雅草卓伊凡
【03】支付宝支付商户申请下户到配置完整流程-对签约申请已通过商户进行开通API支付-创建应用-申请支付宝公钥-应用公钥-支付宝密钥-配合支付宝官方证书生成工具+配置完整流程-优雅草卓伊凡
22 0
【03】支付宝支付商户申请下户到配置完整流程-对签约申请已通过商户进行开通API支付-创建应用-申请支付宝公钥-应用公钥-支付宝密钥-配合支付宝官方证书生成工具+配置完整流程-优雅草卓伊凡
小红书笔记详情 API 接口:获取、应用与收益全解析
小红书(RED)是国内领先的生活方式分享平台,汇聚大量用户生成内容(UGC),尤以“种草”笔记闻名。小红书笔记详情API接口为开发者提供了获取笔记详细信息的强大工具,包括标题、内容、图片、点赞数等。通过注册开放平台账号、申请API权限并调用接口,开发者可构建内容分析工具、笔记推荐系统、数据爬虫等应用,提升用户体验和运营效率,创造新的商业模式。本文将详细介绍该API的获取、应用及潜在收益,并附上代码示例。
180 13
阿里巴巴热卖商品推荐 API 接口的开发、应用与收益
阿里巴巴热卖商品推荐API为开发者提供了获取平台热卖商品信息的强大工具,涵盖商品标题、价格、销量等数据。通过注册开放平台账号、申请API权限并调用接口,开发者可构建热卖商品推荐系统、数据分析工具及供应链管理系统等应用,提升用户体验与运营效率,创造新的商业模式。该API采用RESTful风格,支持多种应用场景,助力电商从业者实现创新与增值。
126 7
1688APP 原数据 API 接口的开发、应用与收益
1688作为阿里巴巴旗下的B2B平台,汇聚海量供应商和商品资源。其APP原数据API接口为开发者提供获取商品详细信息的强大工具,涵盖商品标题、价格、图片等。通过注册开放平台账号、申请API权限并调用接口,开发者可构建比价工具、供应链管理及自动化上架工具等应用,提升用户体验与运营效率,创造新的商业模式。示例代码展示了如何使用Python调用API并解析返回结果。
101 8
亚马逊详情 API 接口的开发、应用与收益
亚马逊详情API接口是亚马逊开放平台提供的强大工具,允许开发者编程获取商品的详细信息,如标题、价格、描述等。通过注册账号、申请权限并调用API,开发者可构建比价工具、推荐系统和数据分析工具等应用,提升用户体验与运营效率,创造新商业模式。本文详细介绍其开发流程、应用场景及潜在收益,并附代码示例。
50 6
淘宝评论与商品详情数据API接口的使用与应用
商品详情数据API:获取商品的基本信息(如标题、价格、库存、描述等)。 评论数据API:获取商品的用户评价数据(如评分、评论内容、用户昵称、购买时间等)。
深度解析淘宝商品评论API接口:技术实现与应用实践
淘宝商品评论API接口是电商数据驱动的核心工具,帮助开发者高效获取用户评价、画像及市场趋势。其核心功能包括多维度信息采集、筛选排序、动态更新、OAuth 2.0认证和兼容多种请求方式。通过该接口,开发者可进行商品优化、竞品分析、舆情监控等。本文详细解析其技术原理、实战应用及挑战应对策略,助力开启数据驱动的电商运营新篇章。

热门文章

最新文章

相关课程

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等