作者:nuysoft/高雲 QQ:47214707 Email:nuysoft@gmail.com
聲明:本文為原創文章,如需轉載,請註明來源並保留原文連結。
jQuery源碼分析系列(持續更新)
1. DOM遍曆有3個核心函數:
| jQuery.dir( elem, dir, until ) |
從一個元素出發,迭代檢索某個方向上的所有元素並記錄,直到與遇到document對象或遇到until匹配的元素 |
| jQuery.nth( cur, result, dir, elem ) |
從一個元素出發,迭代檢索某個方向上的第N個元素 |
| jQuery.sibling( n, elem ) |
元素n的所有後續兄弟元素,包含n,不包含elem |
jQuery對象上的DOM遍曆方法(大部分)被轉換對這3個核心函數的調用,而這3個核心函數最後又都轉換為對原生API的操作,看看他們之間的關係:
| 核心函數 |
jQuery對象方法 |
含義 |
用到的原生API |
| jQuery.dir |
parents |
祖先元素 |
parentNode |
| |
parentsUntil |
祖先元素,但是不包括until |
parentNode |
| |
nextAll |
所有的兄弟元素 |
nextSibling |
| |
prevAll |
所有的兄長元素 |
previousSibling |
| |
nextUntil |
所有的兄弟元素,但是不包括until |
nextSibling |
| |
prevUntil |
所有的兄長元素,但是不包括until |
previousSibling |
jQuery.nth |
next |
下一個兄弟元素 |
nextSibling |
| |
prev |
上一個兄長元素 |
previousSibling |
jQuery.sibling |
siblings |
所有兄長、兄弟元素,不包括當前元素 |
elem.parentNode.firstChild |
| |
children |
所有的子節點 |
elem.firstChild |
2. jQuery.dir( elem, dir, until )
/** * 從一個元素出發,迭代檢索某個方向上的所有元素並記錄,直到與遇到document對象或遇到until匹配的元素 * 迭代條件(簡化):cur.nodeType !== 9 && !jQuery( cur ).is( until ) * elem起始元素 * dir迭代方向,可選值:parentNode nextSibling previousSibling * until選取器運算式,如果遇到until匹配的元素,迭代終止 */dir: function( elem, dir, until ) { // 這個函數很精髓,短短几行代碼,支援遍曆祖先、所有兄長、所有兄弟!var matched = [], // 匹配結果cur = elem[ dir ]; // 第一次訪問,嘗試在方向dir上取一次,為迴圈提供第一次判斷(變數cur多餘,只用elem就可滿足)// 不包含自身/** * 迭代訪問,直到遇到document對象或遇到until匹配的元素 * cur.nodeType !== 9當前DOM節點cur不是document對象 * !jQuery( cur ).is( until )當前DOM節點cur不匹配運算式until * * until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until ) * 這個布林運算式也有點意思,執行最後的jQuery.is的隱含條件是:until !== undefined && cur.nodeType === 1 * 複合的布林運算式和三元運算式,能減少程式碼數、稍微提升效能,但是代碼晦澀,不易閱讀和維護。 * 也許看不懂也是jQuery風靡的原因之一 */while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {if ( cur.nodeType === 1 ) { // 如果是Element,則放入匹配結果數組matched.push( cur );}cur = cur[dir]; // 將方向dir上的下一個節點,設定為當前節點,繼續訪問}return matched;} |
3. jQuery.nth( cur, result, dir, elem )
/** * 從一個元素出發,迭代檢索某個方向上的第N個元素 * cur起始元素 * result第幾個,1表示當前元素,2表示下一個,以此類推(搞不明白為什麼從1開始?) * dir迭代方向 * elem多餘 */nth: function( cur, result, dir, elem ) {result = result || 1; // 第幾個?預設從1開始?嗯,這裡從1開始計數,1表示當前元素,2表示下一個,以此類推var num = 0; // 操蛋的初始值,初始為1更好理解// 下邊的for迴圈看的蛋疼!// dir先在方向dir上取一次再迴圈,nth先迴圈一次然後再取// dir不包含自身,nth包含自身for ( ; cur; cur = cur[dir] ) { // 某個方向if ( cur.nodeType === 1 && ++num === result ) { // 先加後取值,num等於1時檢查的是當前元素break;}}// 如果result為0或1,則取當前元素// 如果result小於0,則返回undefinedreturn cur;} |
4. jQuery.nth( cur, result, dir, elem )
/** * 元素n的所有後續兄弟元素,包含n,不包含elem * n起始元素(包含在返回結果中) * elem排除元素 */sibling: function( n, elem ) {var r = [];for ( ; n; n = n.nextSibling ) { // 先判斷再取,結果中包含n// nodeType === 1,只能是Element,過濾了其他的Text、Attr、Comment等元素if ( n.nodeType === 1 && n !== elem ) {r.push( n );}}return r;} |