jQueryソース分析のparents,parentsUntil,next,prev,nextAll,prevAll,nextUntil,prevUntil,siblings,children

8306 ワード

parents,parentsUntil,next,prev,nextAll,prevAll,nextUntil,prevUntil,siblings,children,contentsこれらのインスタンス関数を抽出してテストします.ソースコードは次のとおりです.
jQuery.dirメソッド:
  dir: function( elem, dir, until ) {
		//        
		var matched = [],
		cur = elem[ dir ];
//  nextUntil     until,   parents    ,  parents        .   until  undefined,        parentNode
//    jQuery                                      
//           until    ,         !
		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;
	}

jQuery.Siblingsメソッドソース:(2番目のパラメータは終了パラメータ)
sibling: function( n, elem ) {
		var r = [];
		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}

Siblingメソッド:
function sibling( cur, dir ) {//  next/pre           ,      sibling(elem,"previousSibling")
	do {
		cur = cur[ dir ];
	} while ( cur && cur.nodeType !== 1 );
	return cur;
}

parentsメソッドソース:
jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
  //dir parentNode,  var $parents3 = $p.parents(".bar");
 //   parents       $p    DOM  $p[i],              until      arguments[1]
 //          $p.parents(".bar");  until ".bar"   arguments[1]  ".bar"
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return sibling( elem, "nextSibling" );
	},
	prev: function( elem ) {
		return sibling( elem, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	//nextUntil  ,      $p[i],       DOM     ,util         
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
		//prevUntil  
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.merge( [], elem.childNodes );
	}
}, function( name, fn ) {
       //jQuery.fn[ "parents"]     ,      。      $p.parents(".bar");        
 jQuery.fn[ name ] = function( until, selector ) {
      /* $p         fn  ,       parents  ,      Array  ,until      ,   ".bar"。   this  $p,          fn,   parents  ,            this[i],   DOM  ,      parents      DOM  。   fn       DOM     ,      $.map    ,     fn  ,         ,  jQuery.map  。    fn      true,   ret    。*/
              var ret = jQuery.map( this, fn, until );  
 //    parentsUntil ,            ,   selector          until,   ".bar"
 //   parentsUtil          ,    until,     until        ,dir  
		if ( name.slice( -5 ) !== "Until" ) {
			selector = until;
		}
 //  selector  ,   selector        ret    !
		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}
  //  $p        1,    $p[0],$p[i]            !
		if ( this.length > 1 ) {
			// Remove duplicates
			if ( !guaranteedUnique[ name ] ) {
				ret = jQuery.unique( ret );
			}
 // Reverse order for parents* and prev-derivatives</span>
//var rparentsprev = /^(?:parents|prev(?:Until|All))/,</span>
//   parents,prev        
			if ( rparentsprev.test( name ) ) {
				ret = ret.reverse();
			}
		}

		return this.pushStack( ret );
	};
});

注意:他の接尾辞はuntilの方法ではなく、selectorが選択した結果を選択することを示すパラメータしか入力できません.ここのjQuery.mapは3番目のパラメータを入力し、その中のfnは3つのパラメータを入力します.それぞれ、DOM要素、DOM要素の下付き、余分なuntilパラメータはprevUntilなどのuntilメソッドに使用され、検索を停止するフラグとして使用されます.
next: function( elem ) {
		return sibling( elem, "nextSibling" );
	}
nextは呼び出しオブジェクトのすべての次の同級のオブジェクトからなる集合を取得し、なぜすべてのDOMの次の兄弟ノードをjQueryから真の集合を構成することができるのか.mapの役割.実は各DOMの次の兄弟ノードを巡るときに返されるのは配列で、jQuery.mapで[]が呼び出された.concat.apply([],ret);
nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	}
nextで呼び出されたsiblingsは、同じ方向の要素のみを取得する方法です.nextAllが呼び出したのはjQueryですdir、彼は指定した方向のすべての要素を取得して、untilが終わることを知っています
function sibling( cur, dir ) {//  next/pre           ,      sibling(elem,"previousSibling")
	do {
		cur = cur[ dir ];
	} while ( cur && cur.nodeType !== 1 );
	return cur;
}
prevメソッドは、指定された方向の要素を取得し、呼び出された要素は依然としてsiblingsメソッドである.
prev: function( elem ) {
		return sibling( elem, "previousSibling" );
	}
prevAllがjQueryを呼び出す.dir,この方法は同方向のすべての要素を取得する
prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	}
parent要素取得
直接親要素
parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	}
でparentsはjQueryを使用しています.dir指定した方向のすべての要素を取得
parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	}
nextall同方向のすべての要素を取得
nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	}

jQuery.Siblingsは、すべての兄弟要素を取得するために使用されます.
sibling: function( n, elem ) {
		var r = [];
		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {//     
				r.push( n );
			}
		}

		return r;
	}
siblingsメソッドを見てみましょう
	siblings: function( elem ) {
		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
	}
この関数は自分自身を返さないで、ただ自分のすべての同級要素を返します!
childrenメソッドは、エレメントのすべてのサブエレメントを取得しますが、Elementタイプのエレメントのみが含まれます.
children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	}
contentsインスタンスメソッドiframeならcontentWindowを取得する.documentまたはcontentDocument.iframeでなければ結果にはすべてが含まれます
childNodes集合
contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.merge( [], elem.childNodes );
	}
すべてのuntilの末尾の要素に対してjQuery.dirは、3番目のパラメータが検索を終了する要素を表す.
私たちが呼び出すとき、この方法にパラメータを入力するだけであれば、このパラメータはuntilであり、2つのパラメータを入力する最初のパラメータがuntilであれば、2番目のパラメータがselectorであり、つまりuntilタイプの方法の最初のパラメータは必ずuntilである!
parentUtil指定した要素の最後まですべての親要素を取得
parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	}
prevUtil指定された要素まですべての兄弟要素を取得
prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	}
nextUtil特定のエレメントが終了するまで、指定した兄弟エレメントを取得
nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	}

まとめ:
(1)parents等の方法は、まず、各呼び出しオブジェクトのDOMオブジェクトに対して対応するdir又はsiblingsメソッドを呼び出し、結果配列を得る.次にparentsなどの方法のパラメータをセレクタとして結果配列をフィルタリングし,有効な結果を得た!parentsUtilsでは、2番目のパラメータutilが入力される可能性があります.dirメソッドでは、そのutilパラメータに対してparentNodeの移動を終了し、返された結果を最初のパラメータで再計算します.考え方:先に選んでからやり直す
(2)nextUtilなどが1つのパラメータだけを入力した場合、このパラメータはuntilであり、2つのパラメータを入力した場合、最初のパラメータはuntilであり、2番目のパラメータはselectorであり(つまり、この場合はUntilがあることを示している場合、最初のパラメータは必ずuntilである)、前のステップで選択した結果をさらにフィルタするために使用される!untilタイプでない場合は、selectorというパラメータが1つしか入力されません.
(3)untilのときに入ってきた3番目のパラメータがそのままコールバック関数に入ってくることがわかりますので、jQueryオブジェクトではなくDOMオブジェクトであることに注意してください
var result=$("#n7").prevUntil($('#n5')[0]);//DOM  
console.log(result);