继续介绍选择器的其它原理,包括内容,可见性,属性,子元素,表单,表单对象属性等等原理。
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达到了过滤的目的。