我們已經使用了帶有簡單Css選擇器的jQuery選取函數:$()。現在是時候深入了解jQuery選擇器語法,以及一些提取和擴充選中元素集的方法了。
一、jQuery選擇器
在CSS3選擇器標淮草案定義的選擇器語法中,jQuery支持相當完整的一套子集,同時還添加了一些非標準但很有用的偽類。注意:本節講述的是 jQuery選擇器。其中有不少選擇器(但不是全部)可以在CSS樣式表中使用。選擇器語法有三層結構。你肯定已經見過選擇器中最簡單的形式。”#te st”選取id屬性為”test”的元素。”blockquote”選取文檔中的所有<blockquote>元素,而”div.note” 則選取所有class屬性為”note”的<blockquote>元素。簡單選擇器可以組合成“組合選擇器”,比如 “div.note>p”和“blockquote i”,只要用組合字符做分隔符就行。簡單選擇器和組合選擇器還可以分組成逗號分隔的列表。這種選擇器組是傳遞給$()函數最常見的形式。在解釋組合選擇器 和選擇器組之前,我們必須先了解簡單選擇器的語法。
1、簡單選擇器
簡單選擇器的開頭部分(顯式或隱式地)是標簽類型聲明。例如,如果只對<P>元素感興趣,簡單選擇器可以用“P”開頭。如果選取的元素和標簽名無關,則可以使用通配符“*”號來代替。如果選擇器沒有以標簽名或通配符開頭,則隱式含有一個通配符。
標簽名或通配符指定了備選文檔元素的一個初始集。在簡單選擇器中,標簽類型聲明之后的部分由零個或多個過濾器組成。過濾器從左到右應用,和書寫順序一致,其中每一個都會縮小選中元素集。下表列舉了jQuery支持的過濾器。
jQuery選擇過濾器
過濾器含義
#id匹配id屬性為id的元素。在有效的}ITML文檔中,永遠不會出現多個元素擁有相同的ID,因此該過濾器通常作為獨立選擇器來使用
.class匹配class屬性(是一串被解析成用空格分隔的單詞列表)含有class單詞的所有元素
[attr]匹配擁有attr屬性(和值無關)的所有元素
[attr=val]匹配擁有attr屬性且值為val的所有元素
[attr!=val]匹配沒有attr屬性、或attr屬性的值不為val的所有元素((jQuery的擴展)
[attr^=val]匹配attr屬性值以val開頭的元素
[attr$=val]匹配attr屬性值以val結尾的元素
[attr*=val]匹配attr屬性值含有val的元素
[attr~=val]當其attr屬性解釋為一個由空格分隔的單詞列表時,匹配其中包含單詞val的元素。因此選擇器“div.note”與“div [class~=note]”相同
[attr|=val]匹配attr屬性值以val開頭且其后沒有其他字符,或其他字符是以連字符開頭的元素
:animated匹配正在動畫中的元素,該動畫是由jQuery產生的
:button匹配<button type=”button”>和<input type=”button”>元素(jQuery的擴展)
:checkbox匹配<input type=”checkbox”>元素( jQuery的擴展),當顯式帶有input標簽前綴”input:checkbox”時,該過濾器更高效
:checked匹配選中的input元素
:contains(text)匹配含有指定text文本的元素(jQuery的擴展)。該過濾器中的圓括號確定了文本的范圍—無須添加引號。被過濾的元素的文本是由textContent或innerText屬性來決定的—這是原始文檔文本,不帶標簽和注釋
:disabled匹配禁用的元素
:empty匹配沒有子節點、沒有文本內容的元素
:enabled匹配沒有禁用的元素
:eq(n)匹配基于文檔順序、序號從0開始的選中列表中的第n個元素(jQuery的擴展)
:even匹配列表中偶數序號的元素。由于第一個元素的序號是0,因此實際上選中的是第1個、第3個、第5個等元素(jQuery的擴展)
:file匹配<input type=”file”>元素(jQuery的擴展)
:first匹配列表中的第一個元素。和“:eq(0)”相同(jQuery的擴展)
:first-child匹配的元素是其父節點的第一個子元素。注意:這與“:first”不同
:gt(n)匹配基于文檔順序、序號從0開始的選中列表中序號大于n的元素( jQuery的擴展)
:has(sel)匹配的元素擁有匹配內嵌選擇器sel的子孫元素
:header匹配所有頭元素:<h1>, <h2>, <h3>, <h4>, <h5>或<h6> (jQuery的擴展)
:hidden匹配所有在屏幕上不可見的元素:大體上可以認為這些元素的offsetWidth和offsetHeight為0
:image匹配<input type=”image”>元素。注意該過濾器不會匹配<img>元素( jQuery的擴展)
:input匹配用戶輸入元素:<input>, <textarea>, <select>和<button>( jQuery的擴展)
:last匹配選中列表中的最后一個元素(( jQuery的擴展)
:last-child匹配的元素是其父節點的最后一個子元素。注意:這與“:last”不同
:lt(n)匹配基于文檔順序、序號從0開始的選中列表中序號小于n的元素( jQuery的擴展)
:not(sel)匹配的元素不匹配內嵌選擇器sel
:nth(n)與“:eq(n)”相同(jQuery的擴展)
:nth-child(n)匹配的元素是其父節點的第n個子元素。。可以是數值、單詞even,單詞odd或計算公式。 使用“:nth-child(even)”來選取那些在其父節點的子元素中排行第2或第4等序號的元素。使用“:nth-child(odd)”來選取那 些在其父節點的子元素中排行第1、第3等序號的元素。
更常見的情況是,n是xn或x n+y這種計算公式,其中x和y是整數,n是字面量n。因此可以用nth-child(3n+1)來選取第1個、第4個、第7個等元素。
注意該過濾器的序號是從1開始的,因此如果一個元素是其父節點的第一個子元素,會認為它是奇數元素,匹配的是3n+1,而不是3n。要和“:even以及“:odd”過濾器區分開來,后者匹配的序號是從0開始的。
:odd匹配列表中奇數(從0開始)序號的元素。注意序號為1和3的元素分別是第2個和第4個匹配元素( jQuery的擴展)
:only-child匹配那些是其父節點唯一子節點的元素
:parent匹配是父節點的元素,這與“:empty”相反(jQuery的擴展)
:password匹配<input type=”password”>元素(jQuery的擴展)
:radio匹配<input type=”radio”>元素( j Query的擴展)
:reset匹配<input type=”reset”>和<button type=”reset”>元素(jQuery的擴展)
:selected匹配選中的<option>元素。使用“:checked”來選取選中的復選框和單選框(jQuery的擴展)
:submit匹配<input type=”submit”>和<button type=”submit”>元素(jQuery的擴展)
:text匹配<input type=”text”>元素(jQuery的擴展)
:visible匹配所有當前可見的元素:大體上可以認為這些元素的offsetWidth和offsetHeight的值不為0,這和“:hidden”相反
注意:表中列舉的部分選擇器在圓括號中接受參數。例如,下面這個選擇器選取的元素在其父節點的子元素中排行第1或第2等,只要它們含有“JavaScript”單詞,就不包含元素。
p:nth-child(3n+1): text (JavaScript):not(:has(a))
通常來說,指定標簽類型前綴,可以讓過濾器的運行更高效。例如,不要簡單使用”:radio”來選取單選框按鈕,使用“input:radio”會更好。ID過濾器是個例外,不添加標簽前綴時它會更高效。例如,選擇器“#address”通常比更明確的“form#address”更高效。
2、組合選擇器
使用特殊操作符或“組合符”可以將簡單選擇器組合起來,表達文檔樹中元素之間的關系。下表列舉了jQuery支持的組合選擇器。這些組合選擇器與CSS3支持的組合選擇器是一樣的。
下面是組合選擇器的一些例子:
1
2
3
4
"blockquote i" //匹配<blockquote>里的<i>元素
"ol > li" //<1i>元素是<of>的直接子元素
"#output+*" //id="output"元素后面的兄弟元素
"div.note > h1+p" //緊跟<h1>的<P>元素,在<div class="note">里面
注意組合選擇器并不限于組合兩個選擇器:組合三個甚至更多選擇器也是允許的。組合選擇器從左到右處理。
3、選擇器組
傳遞給$()函數(或在樣式表中使用)的選擇器就是選擇器組,這是一個逗號分隔的列表,由一個或多個簡單選擇器或組合選擇器構成。選擇器組匹配的元素只要匹配該選擇器組中的任何一個選擇器就行。對我們來說,一個簡單選擇器也可以認為是一個選擇器組。下面是選擇器組的一些例子:
1
2
3
4
"h1, h2,h3" //匹配<h1>, <h2>和<h3>元素
"#p1, #p2, #p3" //匹配id為p1, p2或p3的元素
"div.note, p.note" //匹配class="note"的<div>和<P>元素
"body>p,div.note>p" //<body>和<div class="note">的<P>子元素
注意:CSS和jQuery選擇器語法允許在簡單選擇器的某些過濾器中使用圓括號,但并不允許使用圓括號來進行更常見的分組。例如,不能把選擇器組或組合選擇器放在圓括號中并且當成簡單選擇器:
1
2
(h1, h2, h3)+p //非法
h1+p, h2+p, h3+p //正確的寫法
二、選取方法
除了$()函數支持的選擇器語法,jQuery還定義了一些選取方法。本章中我們已看到過的大部分jQuery方法都是在選中元素上執行某種操作。選取方法不一樣:它們會修改選中元素集,對其進行提取、擴充或僅作為新選取操作的起點。
本節描述這些選取方法。你會注意到這些選取方法中的多數提供的功能與選擇器語法的功能是一樣的。
提取選中元素最簡單的方式是按位置提取。first()返回的jQuery對象僅包含選中元素中的第一個,last()返回的jQuery對象則只包含最后一個元素。更通用的是,eq()方法返回物Query對象只包含指定序號的單個選中元素。(在jQuery 1.4中,負序號也是允許的,會從選區的末尾開始計數。)注意這些方法返回的jQuery對象只含有一個元素。這與常見的數組序號是不一樣的,數組序號返回的單一元素沒有經過jQuery包裝:
1
2
3
4
5
6
var paras=$("p");
paras.first() //僅選取第一個<p>元素
paras.last() //僅選取最后一個<P>
paras.eq(1) //選取第二個<P>
paras.eq(-2) //選取倒數第二個<P>
paras[1] //第二個<P>元素自身
通過位置提取選區更通用的方法是slice()o jQuery的slice()方法與Array.slice()方法類似:前者接受開始和結束序號(負序號會從結尾處計算),返回的jQuery對象包含從開始到結束序號(但不包含結束序號)處的元素集。如果省略結束序號,返回的對象會包含從開始序號起的所有元素:
1
2
$("p").slice(2,5) //選取第3個、第4個和第5個<P>元素
$("div").slice(-3) //選取最后3個<div>元素
filter()是通用的選區過濾方法,有3種調用方式:
傳遞選擇器字符串給filter(),它會返回一}jQuery對象,僅包含也匹配該選擇器的選中元素。
傳遞另一個jQuery對象給filter(),它會返回一個新的jQuery對象,該對象包含這兩們Query對象的交集。也可以傳遞元素數組甚至單一文檔元素給filter()。
傳遞判斷函數給filter(),會為每一個匹配元素調用該函數,filter()則返回一個jQuery對象,僅包含判斷函數為true(或任意真值)的元素。在調用判斷函數時,this值為當前元素,參數是元素序號。1
2
3
$("div").filter(".note") //與$("div.note")一樣
$("div").filter($(".note")) //與$("div.note")一樣
$("div").filter(function(idx){return idx%2 == 0}) //與$("div:even")一樣
not()方法與filter()一樣,除了含義與filter()相反。如果傳遞選擇器字符串給not()它會返回一個新的jQuery對象,該對象只包含不匹配該選擇器的元素。如果傳遞jQuery對象、元素數組或單一元素給not(),它會返回除了顯式排除的元素之外的所有選中元素。如果傳遞判斷函數給not(),該判斷函數的調用就與在filter()中一樣,只是返回的jQuery對象僅包含那些使得判斷函數返回false或其他假值的元素:
1
$("div").not("#header, #footer"); //除了兩個特殊元素之外的所有元素
在jQuery 1.4中,提取選區的另一種方式是has()方法。如果傳入選擇器,has()會返回一個新的jQuery對象,僅包含有子孫元素匹配該選擇器的選中元素。如果傳入文檔元素給has(),它會將選中元素集調整為那些是指定元素祖先節點的選中元素:
1
$("p").has("a[href]") //包含鏈接的段落
add()方法會擴充選區,而不是對其進行過濾或提取。可以將傳給$()函數的任何參數(除了函數)照樣傳給add()方法。add()方法會返回原來的選中元素,加上傳給$()函數的那些參數所選中(或創建)的那些元素。add()會移除重復元素,并對該組合選區進行排序,以便里面的元素按照文檔中的順序排列:
1
2
3
4
5
6
//選取所有<div>和所有<P>元素的等價方式
$("div, p") //使用選擇器組
$("div").add(p) //給add()傳入選擇器
$("div").add($("p")) //給add()傳入jQuery對象
var paras = document.getElementsByTagName("p"); //類數組對象
$("div").add(paras); //給add()傳入元素數組
1.將選中元素集用做上下文
上面描述的filter(). add()、和not()方法會在各自的選中元素集上執行交集、并集和差集運算。jQuery還定義一些其他選取方法可將當前選中元素集作為上下文來使用。對選中的每一個元素,這些方法會使用該選中元素作為上下文或起始點來得到新的選中元素集,然后返回一個新的jQuery對象,包含所有新的選中元素的并集。與add()方法類似,會移除重復元素并進行排序,以便元素會按照在文檔中出現的順序排列好。
該類別選取方法中最通用的是find()。它會在每一個當前選中元素的子孫元素中尋找與指定選擇器字符串匹配的元素,然后它返回一個新的jQuery對象來代表所匹配的子孫元素集。注意這些新選中的元素不會并入已存在的選中元素集中。同時注意find()和filter()不同,filter()不會選中新元素,只是簡單地將當前選中的元素集進行縮減:
1
$("div").find("p") //在中查找元素,與$("div p")相同
該類別中的其他方法返回新的jQuery對象,代表當前選中元素集中每一個元素的子元素、兄弟元素或父元素。大部分都接受可選的選擇器字符串作為參數。不傳入選擇器時,它們會返回所有子元素、兄弟元素或父元素。傳入選擇器時,它們會過濾元素集,僅返回匹配的。
children()方法返回每一個選中元素的直接子元素,可以用可選的選擇器參數進行過濾:
1
2
3
//尋找id為"header"和"footer"元素的子節點元素中的所有<span>元素
//與$("#header>span, #footer>span")相同
$("#header, #footer").children("span")
contents()方法與children()方法類似,不同的是它會返回每一個元素的所有子節點,包括文本節點。如果選中元素集中有<iframe>元素,contents()還會返回該<iframe>內容的文檔對象。注意contents()不接受可選的選擇器字符串參數—因為它返回的文檔節點不完全是元素,而選擇器字符串僅用來描述元素節點。
next()和prev()方法返回每一個選中元素的下一個和上一個兄弟元素(如果有的話)。如果傳入了選擇器,會只選中匹配該選擇器的兄弟元素:
1
2
$("h1").next("p") //與$("h1+p")相同
$("h1").prev() //<h1>元素前面的兄弟元素
nextAll()和prevAll()返回每一個選中元素前面或后面的所有兄弟元素(如果有的話)。siblings()方法則返回每一個選中元素的所有兄弟元素(選中元素本身不是自己的兄弟元素)。如果給這些方法傳人選擇器,則只會返回匹配的兄弟元素:
1
2
$("#footer").nextAll("p") //緊跟#footer元素的所有<P>兄弟元素
$("#footer").prevAll() //#footer元素前面的所有兄弟元素
從jQuery 1.4開始,nextUntil()和prevUntil()方法接受一個選擇器參數,會選取選中元素后面或前面的所有兄弟元素,直到找到某個匹配該選擇器的兄弟元素為止。如果省略該選擇器,這兩個方法的作用就和不帶選擇器的nextAll()和prevAll()一樣。
parent()方法返回每一個選中元素的父節點:
1
$("li").parent() //列表元素的父節點,比如<u1>和<ol>元素
parents()方法返回每一個選中元素的祖先節點(向上直到元素)。parent()和parents()都接受一個可選的選擇器字符串參數:
1
$("a[href]").parents("p") //含有鏈接的<P>元素
parentsUntil()返回每一個選中元素的祖先元素,直到出現匹配指定選擇器的第一個祖先元素。closest()方法必須傳人一個選擇器字符串,會返回每一個選中元素的祖先元素中匹配該選擇器的最近一個祖先元素(如果有的話)。對該方法而言,元素被認為是自身的祖先元素。在jQuery 1.4中,還可以給closest()傳入一個祖先元素作為第二個參數,用來阻止jQuery往上查找時超越該指定元素:
1
2
$("a[href]").closest("div") //包含鏈接的最里層<div>
$("a[href]").parentsUntil(":not(div)") //所有包裹<a>的<div>元素
2、恢復到之前的選中元素集
為了實現方法的鏈式調用,很多jQuery對象的方法最后都會返回調用對象。然而本節講述的方法都返回新的jQuery對象。可以鏈式調用下去,但必須清晰地意識到,在鏈式調用的后面所操作的元素集,可能已經不是該鏈式調用開始時的元素集了。
實際情況還要復雜些。當這里所描述的選取方法在創建或返回一個新的ejQuery對象時,它們會給該對象添加一個到它派生自的舊jQuery對象的內部引用。這會創建一個jQuery對象的鏈式表或棧。end()方法用來彈出棧,返回保存的jQuery對象。在鏈式調用中調用end()會將匹配元素集還原到之前的狀態。考慮以下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
//尋找所有<div>元素,然后在其中尋找<P>元素
//高亮顯示<P>元素,然后給<div>元素添加一個邊框
//首先,不使用鏈式調用
var divs = $("div");
var paras = div.find("p");
paras.addClass("highlight");
divs.css("border", "solid black 1px");
//下面展現如何使用鏈式調用來實現
$("div").find("p").addClass("highlight").end().css("border", "solid black 1px");
//還可以將操作調換順序來避免調用end()
$("div").css("border", "solid block 1px").find("p").addClass("highlight");
如果想手動定義選中元素集,同時保持與end()方法的兼容,可以將新的元素集作為數組或類數組對象傳遞給push5tack()方法。指定的元素會成為新的選中元素,之前選中的元素集則會壓入棧中,之后可以用end()方法還原它們:
1
2
3
var sel = $("div"); //選取所有<div>元素
sel.pushStack(document.getElementsByTagName("p")); //修改為所有<P>元素
sel.end(); //還原為<div>元素
既然我們已經講解了end()方法及其使用的選區棧,就有最后一個方法需要講解。andSelf()返回一個新的jQuery對象,包含當前的所有選中元素,加上之前的所有選中元素(會去除重復的)。andSelf()和add()方法一樣,或許“addPrev”是一個更具描述性的名字。作為例子,考慮上面代碼的下述變化:高亮顯示<P>元素及其父節點中的<div>元素,然后給這些<div>元素添加邊框:
1
2
3
4
$("div").find("p").andSelf(). //尋找<div》中的<P>,合并起來
addClass("highlight"). //都高亮
end().end(). //彈出棧兩次,返回$("div")
css("border", "solid black 1px"); //給divs添加邊框