1 jQuery 物件Sizzle.selectors.relative中存放了塊間關係符和相應的塊間關係過濾函式,稱為“塊間關係過濾函式集”
塊間關係符共同擁有4種,其含義和過濾方式如圖所看到的。
在函式Sizzle( selector, context, results, seed )從右向左進行過濾時,塊間關係過濾函式被
呼叫,用於檢查對映集checkSet中的元素是否匹配塊間關係符左側的塊表示式。呼叫時的參
數格式為:
Sizzle.selectors.relative[ 塊間關係符 cur ]( 對映集 checkSet, 左側塊表示式pop,
contextXML );
塊間關係過濾函式接受3個引數:
‰ ‰引數checkSet:對映集,對該元素集合執行過濾操作。
‰ ‰引數part:大多數情況下是塊間關係符左側的塊表示式,該引數也能夠是DOM元素。
‰ ‰引數isXML:布林值,指示是否執行在一個XML文件中。
塊間關係過濾函式實現的3個關鍵過程例如以下:
1)遍歷對映集checkSet。
2)依照塊間關係符查詢每一個元素的兄弟元素、父元素或祖先元素。
3)檢查詢到的元素是否匹配引數part,並替換對映集checkSet中相應位置的元素。
a. 假設引數part是標籤,則檢查詢到的元素其節點名稱nodeName是否與之相等,
假設相等則替換為找到的元素,不相等則替換為false。
b. 假設引數part是DOM元素,則檢查詢到的元素是否與之相等,假設相等則替換
為true,不相等則替換為false。
c. 假設引數part是非標籤字串,則呼叫方法Sizzle.filter( selector, set, inplace, not )過濾。
也就是說,遍歷結束後,對映集checkSet中的元素可能會是兄弟元素、父元素、
祖先元素、true或false。
1 塊間關係符"+"匹配選擇器"prev + next",即匹配全部緊接在元素prev後的兄弟元素
next。比如,$("div + span")、$(".lastdiv + span")。對於從右向左的查詢方式,則是檢查元
素next之前的兄弟元素是否匹配塊表示式prev。
var Expr = Sizzle.selectors = {
relative: {
"+": function(checkSet, part){
//檢查引數是否為字串
var isPartStr = typeof part === "string",
//指示引數part是否為標籤字串
isTag = isPartStr && !rNonWord.test( part ),
//isPartStrNotTag:指示引數part是否是非標籤字串。
isPartStrNotTag = isPartStr && !isTag;
if ( isTag ) {
part = part.toLowerCase();
}
/*
遍歷對映集checkSet,查詢每一個元素的前一個兄弟元素,並替換映
射集checkSet中相應位置的元素,有下面3個邏輯分支:
1 假設未找到兄弟元素,則替換為false。
2 假設找到了兄弟元素,而且引數part是標籤,則檢查兄弟元素的節點名稱nodeName
是否與之相等,假設相等則替換為兄弟元素,不相等則替換為false。
3 假設找到了兄弟元素,而且引數part是DOM元素,則檢查二者是否相等,假設相等
則替換為true,不相等則替換為false。
因此,在遍歷結束後,對映集checkSet中的元素可能會是兄弟元素、true或false。
*/
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
if ( (elem = checkSet[i]) ) {
/*在遍歷兄弟元素的同一時候過濾掉非元素節點,而且僅僅要取到一個兄弟元素就
退出while迴圈。*/
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {
}
checkSet[i] = isPartStrNotTag || elem && elem.node
Name.toLowerCase() === part ?
elem || false :
elem === part;
}
}
/*
假設引數part是非標籤字串,則呼叫方法Sizzle.filter( selector,
set, inplace, not )過濾對映集checkSet。對於引數part是標籤和DOM元素的情況,在前面遍
歷對映集checkSet時已經處理過了。
*/
if ( isPartStrNotTag ) {
Sizzle.filter( part, checkSet, true );
}
},
},
};
2 塊間關係符">"用於選擇器"parent > child",即匹配父元素parent下的子元素child。
比如,$("div + span")、$(".lastdiv + span")。對於從右向左的查詢方式,則是檢查子元素
child的父元素是否匹配塊表示式parent。
var Expr = Sizzle.selectors = {
relative: {
">": function( checkSet, part ) {
var elem,
isPartStr = typeof part === "string",
i = 0,
l = checkSet.length;
/*
假設引數part是標籤,則遍歷對映集checkSet,查詢每一個元素的
父元素,並檢查父元素的節點名稱nodeName是否與引數part相等,假設相等則替換對映集
checkSet中相應位置的元素為父元素,不相等則替換為false。
*/
if ( isPartStr && !rNonWord.test( part ) ) {
part = part.toLowerCase();
for ( ; i < l; i++ ) {
elem = checkSet[i];
if ( elem ) {
var parent = elem.parentNode;
checkSet[i] = parent.nodeName.toLowerCase() === part ?
parent : false;
}
}
} else {
/*
假設引數part不是標籤,則可能是非標籤字串或DOM元素,同
樣遍歷對映集checkSet,查詢每一個元素的父元素,並替換對映集checkSet中相應位置的元
素,在這個過程中有下面2個邏輯分支:
1 假設引數part是非標籤字串,則在遍歷對映集checkSet的過程中,替換對映集
checkSet中相應位置的元素為父元素,遍歷結束後呼叫方法Sizzle.filter( selector, set,
inplace, not )過濾對映集checkSet。
2 假設引數part是元素,則在遍歷對映集checkSet時,檢查每一個元素的父元素是否與
之相等,假設相等則替換對映集checkSet中相應位置的元素為true,不相等則替換為
false。
因此,在遍歷結束後,對映集checkSet中的元素可能會是父親元素、true或false。
*/
for ( ; i < l; i++ ) {
elem = checkSet[i];
if ( elem ) {
checkSet[i] = isPartStr ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( isPartStr ) {
Sizzle.filter( part, checkSet, true );
}
}
},
},
};
元素descendant。比如,$("div button")、$("div .btn")。對於從右向左的查詢方式,則是檢
查後代元素descendant的祖先元素是否匹配塊表示式ancestor。
var Expr = Sizzle.selectors = {
relative: {
"": function(checkSet, part, isXML){
var nodeCheck,
doneName = done++,
checkFn = dirCheck;
/*
1 假設引數part是非標籤字串或DOM元素,則呼叫函式dirCheck()過濾對映集
checkSet。
2 假設引數part是標籤,則呼叫函式dirNodeCheck()過濾對映集checkSet。
呼叫函式dirCheck()和dirNodeCheck()時的引數格式為:
checkFn( 方向 "parentNode/previousSibling", 塊表示式 part, 快取計數器 doneName, 映
射集 checkSet, nodeCheck, isXML )
函式dirCheck()和dirNodeCheck()會遍歷對映集checkSet,查詢每一個元素的祖先元素,
並檢查是否有祖先元素匹配引數part,同一時候替換對映集checkSet中相應位置的元素。
*/
if ( typeof part === "string" && !rNonWord.test( part ) ) {
part = part.toLowerCase();
nodeCheck = part;
checkFn = dirNodeCheck;
}
checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
},
},
};
4 塊間關係符"~"用於選擇器"prev~siblings",即匹配元素prev之後的全部兄弟元
素siblings。比如,$('div~p')。對於從右向左的查詢方式,則是檢查元素siblings之前的
兄弟元素是否匹配塊表示式prev。
Sizzle.selectors.relative["~"]( checkSet, part )的原始碼實現與Sizzle.selectors.relative[""]
( checkSet, part )差點兒一樣,兩者的差別只在於呼叫函式dirCheck()和dirNodeCheck()時第
一個引數的值不同,前者是"previousSibling",後者則是"parentNode"。
相關程式碼例如以下所看到的:
var Expr = Sizzle.selectors = {
relative: {
"~": function( checkSet, part, isXML ) {
var nodeCheck,
doneName = done++,
checkFn = dirCheck;
if ( typeof part === "string" && !rNonWord.test( part ) ) {
part = part.toLowerCase();
nodeCheck = part;
checkFn = dirNodeCheck;
}
checkFn( "previousSibling", part, doneName, checkSet, nodeCheck,
isXML );
}
},
};