Jquery 1.9.1源碼分析系列(十二)之篩選操作
廢話不多說了直接奔入主題了。
jQuery.fn.find( selector )
find接受一個參數(shù)表達式selector:選擇器(字符串)、DOM元素(Element)、jQuery對象。分兩種情況處理:
第一種,如果傳入的參數(shù)是非字符串,則先通過jQuery選擇器將selector查找出來,然后過濾出包含于當(dāng)前jQuery對象所匹配的元素的節(jié)點。
if ( typeof selector !== "string" ) {
self = this;
return this.pushStack( jQuery( selector ).filter(function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
}) );
}
可以看出過濾條件中jQuery.contains( self[ i ], this )是關(guān)鍵,該函數(shù)使用的是Sizzle選擇器中的函數(shù),在Sizzle引擎中有分析,詳情點擊。
第二種,如果選擇器是字符串,調(diào)用jQuery.find (= Sizzle)直接處理
ret = [];
for ( i = 0; i < len; i++ ) {
//第二個參數(shù)是表示context
jQuery.find( selector, this[ i ], ret );
}
//$( selector, context )變成$( context ).find( selector ),需要去重和pushStack
ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;
return ret;
jQuery.fn.closest( selectors, context )
第二個參數(shù)是可選的。函數(shù)用于從當(dāng)前匹配元素開始,逐級向上級選取符合指定表達式的第一個元素,并以jQuery對象的形式返回。
這里的表達式包括:選擇器(字符串)、DOM元素(Element)、jQuery對象。
代碼中的處理步驟為
1.根據(jù)傳遞的參數(shù)先查詢出結(jié)果保存在pos中。
pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0;
2.遍歷當(dāng)前jQuery對象的每一個元素,從這個元素開始,逐級向上級選取符合指定表達式的第一個祖先元素。
for ( ; i < l; i++ ) {
cur = this[i];
while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
ret.push( cur );
break;
}
cur = cur.parentNode;
}
}
return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
parents() 和 .closest() 方法類似,它們都沿 DOM 樹向上遍歷。但區(qū)別也很大closest找到第一個符合條件就截止,parents是找到所有符合條件的集合。
jQuery.fn. parent/ parents/ parentsUntil/ next/ prev/ nextAll/ prevAll/ nextUntil/ prevUntil/ siblings/ children/ contents詳解
以上幾組篩選被放在一起處理,源碼如下
jQuery.each({
parent: function( elem ) {…},
parents: function( elem ) {…},
parentsUntil: function( elem, i, until ) {…},
next: function( elem ) {…},
prev: function( elem ) {…},
nextAll: function( elem ) {…},
prevAll: function( elem ) {…},
nextUntil: function( elem, i, until ) {…},
prevUntil: function( elem, i, until ) {…},
siblings: function( elem ) {…},
children: function( elem ) {…},
contents: function( elem ) {…}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
var ret = jQuery.map( this, fn, until );
//過濾
...
return this.pushStack( ret );
};
});
可以看出,這幾個篩選步驟一致。都是先通過map函數(shù)把當(dāng)前jQuery對象每個匹配的元素代入相應(yīng)的匹配函數(shù)(fn)中獲取出結(jié)果然后在進行后續(xù)的過濾。
我們先看一下后面的過濾(已經(jīng)通過jQuery.map( this, fn, until )獲取到了備選種子ret)
首先,并不是所有的篩選函數(shù)都有until這個參數(shù),只有以Until結(jié)尾的幾個篩選才需要這個參數(shù),其他的篩選只有selector這個參數(shù)。
if ( !runtil.test( name ) ) {
selector = until;
}
其次,如果有選擇器,則通過選擇器過濾一下先前查找結(jié)果ret
if ( selector && typeof selector === "string" ) {
ret = jQuery.filter( selector, ret );
}
然后,guaranteedUnique里面的幾種篩選條件(children/contents/next/prev)在當(dāng)前jQuery對象所匹配的元素個數(shù)有多個的時候,通過每個匹配元素獲取到的結(jié)果保存在結(jié)果集ret中,且不需要去重。其他篩選是要去重的。點擊查看jQuery.unique方法詳解
ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
另外,還需要處理的特殊情況是: 如果當(dāng)前jQuery對象所匹配的元素有多個,則使用parents /prevUntil /prevAll這三種篩選的結(jié)果需要倒序排列。需要倒序的原因:jQuery.unique使用的是Sizzle引擎中的排序函數(shù)Sizzle .uniqueSort,這個排序函數(shù)會根據(jù)文檔最頂層對象到最底層的方式排列。
if ( this.length > 1 && rparentsprev.test( name ) ) {
ret = ret.reverse();
}
最后,返回包裹后的結(jié)果
return this.pushStack( ret );
上面說了主題的框架結(jié)構(gòu),下面說一下這一組篩選器匹配函數(shù)里面用到的兩個函數(shù)jQuery.dir和jQuery. sibling,直接上源碼
//從當(dāng)前元素elem指定的dir對應(yīng)的節(jié)點開始一直查找dir,并將這些節(jié)點保存在matched中,直到循環(huán)終止。注意:結(jié)果中不包含elem節(jié)點
dir: function( elem, dir, until ) {
var matched = [],
cur = elem[ dir ];
while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
if ( cur.nodeType === 1 ) {
matched.push( cur );
}
cur = cur[dir];
}
return matched;
},
//獲取節(jié)點n及其兄弟節(jié)點中非elem的節(jié)點集合r
sibling: function( n, elem ) {
var r = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType === 1 && n !== elem ) {
r.push( n );
}
}
return r;
}
//找到當(dāng)前元素cur的下一個dir為止
function sibling( cur, dir ) {
do {
cur = cur[ dir ];
} while ( cur && cur.nodeType !== 1 );
return cur;
}
jQuery.fn.add( selector, context )和jQuery.fn. addBack( selector )
add函數(shù)是向當(dāng)前匹配元素中添加符合指定表達式的元素,并以jQuery對象的形式返回。add可以接收包括:選擇器(字符串)、HTML內(nèi)容(字符串)、DOM元素(Element)、jQuery對象。處理比較簡單,直接上源碼
add: function( selector, context ) {
var set = typeof selector === "string" ?
jQuery( selector, context ) :
jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
//把selector表達式獲取的結(jié)果集拼接到當(dāng)前對象上
all = jQuery.merge( this.get(), set );
//返回新的拼接結(jié)果
return this.pushStack( jQuery.unique(all) );
}
jQuery.fn.add和jQuery.fn.not相對應(yīng)。jQuery.fn.not后面再說。
jQuery.fn.addBack將之前匹配的元素加入到當(dāng)前匹配的元素中,并以新的jQuery對象的形式返回。
addBack: function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter(selector)
);
}
jQuery.fn.andSelf = jQuery.fn.addBack;
jQuery.fn.not( selector )和jQuery.fn.filter( selector )
not: function( selector ) {
return this.pushStack( winnow(this, selector, false) );
}
filter: function( selector ) {
return this.pushStack( winnow(this, selector, true) );
},
not和filter都是操作本身的集合,not是過濾掉本身集合中滿足過濾條件selector的項,留下其他項。而filter是留下滿足過濾條件selector的項。
關(guān)鍵是function winnow( elements, qualifier, keep )函數(shù)。這個函數(shù)的功能是執(zhí)行相同的過濾或者不過濾的功能。過濾條件qualifier有三種:函數(shù)、DOM節(jié)點、字符串。keep:true表示保留滿足過濾條件的項,false表示保留不滿足過濾條件的項。
winnow的源碼注釋如下
//執(zhí)行相同的過濾或者不過濾的功能
function winnow( elements, qualifier, keep ) {
// Can't pass null or undefined to indexOf in Firefox 4
// Set to 0 to skip string check
qualifier = qualifier || 0;
//如果過濾條件是函數(shù),則通過過濾函數(shù)過濾
if ( jQuery.isFunction( qualifier ) ) {
return jQuery.grep(elements, function( elem, i ) {
var retVal = !!qualifier.call( elem, i, elem );
return retVal === keep;
});
//如果過濾條件是DOM相關(guān)類型,通過比較節(jié)點是否相同來過濾
} else if ( qualifier.nodeType ) {
return jQuery.grep(elements, function( elem ) {
return ( elem === qualifier ) === keep;
});
//如果過濾條件是字符串
} else if ( typeof qualifier === "string" ) {
//過濾出elements中的節(jié)點元素
var filtered = jQuery.grep(elements, function( elem ) {
return elem.nodeType === 1;
});
// 其中isSimple = /^.[^:#\[\.,]*$/
if ( isSimple.test( qualifier ) ) {
return jQuery.filter(qualifier, filtered, !keep);
} else {
//查找filtered中滿足篩選條件qualifier的節(jié)點
qualifier = jQuery.filter( qualifier, filtered );
}
}
//過濾出elements中滿足過濾條件的元素
return jQuery.grep(elements, function( elem ) {
return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
});
}
其中用到j(luò)Query.grep,grep詳解點擊這里。
jQuery.filter( expr, elems, not )這個低級api專門用來處理jQuery.fn.filter中過濾條件為字符串的情況。
jQuery.filter: function( expr, elems, not ) {
if ( not ) {
expr = ":not(" + expr + ")";
}
//其中matchesSelector和matches是Sizzle中的函數(shù)。matchesSelector是判斷單個元素elem是否滿足表達式expr,matches是查找元素集合elems中滿足表達式expr的項
return elems.length === 1 ?
jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
jQuery.find.matches(expr, elems);
},
jQuery.fn.index( elem )
index函數(shù)實際上是一個多功能函數(shù)的集合。
第一個功能:不傳遞elem參數(shù),則表示取當(dāng)前jQuery對象(jQuery對象的第一個元素)在其所有同輩元素中的位置。
if ( !elem ) {
return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
}
第二個功能:如果參數(shù)為String類型則將其視作選擇器,返回當(dāng)前元素在選擇器所匹配的元素中的索引位置。如果該選擇器不匹配任何元素或者當(dāng)前元素不在匹配到的元素內(nèi),則返回-1。
if ( typeof elem === "string" ) {
//在數(shù)組jQuery( elem )中搜索指定的值,并返回其索引值
return jQuery.inArray( this[0], jQuery( elem ) );
}
第三個功能:如果object為DOM元素或jQuery對象,則返回該元素(或該jQuery對象中的第一個元素)在當(dāng)前jQuery對象所匹配的元素中的索引位置。
return jQuery.inArray(elem.jquery ? elem[0] : elem, this );
其他的篩選處理就不分析了??丛创a即可明白。
jquery選擇器
| 選擇器 | 實例 | 選取 |
|---|---|---|
| * | $("*") | 所有元素 |
| #id | $("#lastname") | id="lastname" 的元素 |
| .class | $(".intro") | 所有 class="intro" 的元素 |
| element | $("p") | 所有 <p> 元素 |
| .class.class | $(".intro.demo") | 所有 class="intro" 且 class="demo" 的元素 |
| :first | $("p:first") | 第一個 <p> 元素 |
| :last | $("p:last") | 最后一個 <p> 元素 |
| :even | $("tr:even") | 所有偶數(shù) <tr> 元素 |
| :odd | $("tr:odd") | 所有奇數(shù) <tr> 元素 |
| :eq(index) | $("ul li:eq(3)") | 列表中的第四個元素(index 從 0 開始) |
| :gt(no) | $("ul li:gt(3)") | 列出 index 大于 3 的元素 |
| :lt(no) | $("ul li:lt(3)") | 列出 index 小于 3 的元素 |
| :not(selector) | $("input:not(:empty)") | 所有不為空的 input 元素 |
| :header | $(":header") | 所有標(biāo)題元素 <h1> - <h6> |
| :animated | 所有動畫元素 | |
| :contains(text) | $(":contains('W3School')") | 包含指定字符串的所有元素 |
| :empty | $(":empty") | 無子(元素)節(jié)點的所有元素 |
| :hidden | $("p:hidden") | 所有隱藏的 <p> 元素 |
| :visible | $("table:visible") | 所有可見的表格 |
| s1,s2,s3 | $("th,td,.intro") | 所有帶有匹配選擇的元素 |
| [attribute] | $("[href]") | 所有帶有 href 屬性的元素 |
| [attribute=value] | $("[href='#']") | 所有 href 屬性的值等于 "#" 的元素 |
| [attribute!=value] | $("[href!='#']") | 所有 href 屬性的值不等于 "#" 的元素 |
| [attribute$=value] | $("[href$='.jpg']") | 所有 href 屬性的值包含以 ".jpg" 結(jié)尾的元素 |
| :input | $(":input") | 所有 <input> 元素 |
| :text | $(":text") | 所有 type="text" 的 <input> 元素 |
| :password | $(":password") | 所有 type="password" 的 <input> 元素 |
| :radio | $(":radio") | 所有 type="radio" 的 <input> 元素 |
| :checkbox | $(":checkbox") | 所有 type="checkbox" 的 <input> 元素 |
| :submit | $(":submit") | 所有 type="submit" 的 <input> 元素 |
| :reset | $(":reset") | 所有 type="reset" 的 <input> 元素 |
| :button | $(":button") | 所有 type="button" 的 <input> 元素 |
| :image | $(":image") | 所有 type="image" 的 <input> 元素 |
| :file | $(":file") | 所有 type="file" 的 <input> 元素 |
| :enabled | $(":enabled") | 所有激活的 input 元素 |
| :disabled | $(":disabled") | 所有禁用的 input 元素 |
| :selected | $(":selected") | 所有被選取的 input 元素 |
| :checked | $(":checked") | 所有被選中的 input 元素 |
- Android Tween動畫之RotateAnimation實現(xiàn)圖片不停旋轉(zhuǎn)效果實例介紹
- jQuery1.9.1針對checkbox的調(diào)整方法(prop)
- jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之綁定事件
- jQuery-1.9.1源碼分析系列(十)事件系統(tǒng)之事件體系結(jié)構(gòu)
- jQuery-1.9.1源碼分析系列(十)事件系統(tǒng)之事件包裝
- Jquery1.9.1源碼分析系列(六)延時對象應(yīng)用之jQuery.ready
- jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之主動觸發(fā)事件和模擬冒泡處理
- Jquery-1.9.1源碼分析系列(十一)之DOM操作
- jQuery-1.9.1源碼分析系列(十一)DOM操作續(xù)之克隆節(jié)點
- jQuery 1.9.1源碼分析系列(十三)之位置大小操作
- jQuery 1.9.1源碼分析系列(十四)之常用jQuery工具
- jQuery 1.9.1源碼分析系列(十五)動畫處理之緩動動畫核心Tween
相關(guān)文章
jquery如何改變html標(biāo)簽的樣式(兩種實現(xiàn)方法)
對于如何修飾html標(biāo)簽,這對于js來說,可以通過setAttribute來設(shè)置標(biāo)簽的屬性,通過getAttribute來得到標(biāo)簽的屬性,而在jq中當(dāng)然也可以實現(xiàn)類似的功能,方法上肯定比js要簡化多了,接下來介紹實現(xiàn)方法,感興趣的朋友可以了解下2013-01-01
用jquery統(tǒng)計子菜單的條數(shù)示例代碼
統(tǒng)計子菜單條數(shù)的方法有很多,在本文為大家詳細介紹下使用jquery是如何實現(xiàn)的,感興趣的朋友不要錯過2013-10-10
jQuery Ajax 加載數(shù)據(jù)時異步顯示加載動畫
這篇文章主要介紹了jQuery Ajax 加載數(shù)據(jù)時異步顯示加載動畫的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-08-08
getJSON調(diào)用后臺json數(shù)據(jù)時函數(shù)被調(diào)用兩次的原因猜想
近期在做前端開發(fā)時候使用到getJSON調(diào)用后臺json數(shù)據(jù),發(fā)現(xiàn)后臺的函數(shù)被調(diào)用兩次,函數(shù)名稱為getMessages,下面是本人的一些猜想,感興趣的朋友可以參考下2013-09-09
jquery如何根據(jù)值設(shè)置默認(rèn)的選中項
這篇文章主要介紹了jquery如何根據(jù)值設(shè)置默認(rèn)的選中項,需要的朋友可以參考下2014-03-03
使用jQuery實現(xiàn)WordPress中的Ctrl+Enter和@評論回復(fù)
相信大家對QQ中的Ctrl+Enter快捷回復(fù)和微博上的@指名回復(fù)功能都不陌生,在WordPress的評論欄方面我們同樣可以添加這樣的功能,一起來看使用jQuery實現(xiàn)WordPress中的Ctrl+Enter和@評論回復(fù)的方法:2016-05-05

