首页 > 代码库 > JQuery日记 6.3 JQuery遍历模块

JQuery日记 6.3 JQuery遍历模块

jQuery.extend({
	// 返回elem延DOM树某个方向访问的所有节点,直到遇到until条件
	dir: function( elem, dir, until ) {
		var matched = [],
			truncate = until !== undefined;

		while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
			if ( elem.nodeType === 1 ) {
				if ( truncate && jQuery( elem ).is( until ) ) {
					break;
				}
				matched.push( elem );
			}
		}
		return matched;
	},
	
	//返回n的兄弟节点(把n,elem设为相同元素时,不返回本身)
	sibling: function( n, elem ) {
		var matched = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				matched.push( n );
			}
		}

		return matched;
	}
});

jQuery.fn.extend({
	has: function( target ) {
		// 以当前jquery对象为上下文查找target
		var targets = jQuery( target, this ),
			l = targets.length;
		// 过滤掉当前JQuery不包含target后代的元素
		return this.filter(function() {
			var i = 0;
			for ( ; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},
	
	// 返回包含符合selector元素的最近的JQuery对象
	// 返回的可能是其包含自己或其父类的JQuery对象,其长度为0或1
	closest: function( selectors, context ) {
		var cur,
			i = 0,
			l = this.length,
			matched = [],
			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( ; i < l; i++ ) {
			// 从本身开始,然后沿父类继续
			for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
				// Always skip document fragments
				// 如果pos是以$(selectors,context)查找出的JQuery对象
				if ( cur.nodeType < 11 && (pos ?
					// pos中是否可查找到cur元素
					pos.index(cur) > -1 :
					// 否则查看cur是否满足selectors选择表达式
					// Don't pass non-elements to Sizzle
					cur.nodeType === 1 &&
						jQuery.find.matchesSelector(cur, selectors)) ) {

					matched.push( cur );
					break;
				}
			}
		}

		return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {

		// No argument, return index in parent
		// 没有传入参数返回在同辈元素中的位置
		if ( !elem ) {
			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
		}

		// index in selector
		// 参数是选择器
		if ( typeof elem === "string" ) {
			// 返回本JQuery对象第一个元素在匹配所有此选择器的JQuery对象的位置
			return indexOf.call( jQuery( elem ), this[ 0 ] );
		}

		// Locate the position of the desired element
		// 返回参数元素在此JQuery对象的位置
		return indexOf.call( this,

			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[ 0 ] : elem
		);
	},
	
	// 在当前JQuery对象中添加额外元素
	add: function( selector, context ) {
		return this.pushStack(
			jQuery.unique(
				jQuery.merge( this.get(), jQuery( selector, context ) )
			)
		);
	},
	
	// 将调用链上前一个JQuery中的元素添加到当前JQuery对象中
	// selector参数用于过滤前一个JQuery对象
	addBack: function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter(selector)
		);
	}
});

// 沿DOM树某个方向获取下一个DOM元素
function sibling( cur, dir ) {
	// 一直遇到DOM元素再停下
	while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
	return cur;
}
// 绑定快捷遍历JQuery对象方法
jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	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: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	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 );
	},
	// frame里的所有子元素
	contents: function( elem ) {
		return elem.contentDocument || jQuery.merge( [], elem.childNodes );
	}
}, function( name, fn ) {
	// 在JQuery的原型对象上绑定快捷遍历函数
	jQuery.fn[ name ] = function( until, selector ) {
		// this指调用此方法的JQuery对象
		// 根据不同遍历的fn,将this中的元素映射成其遍历后的元素
		var matched = jQuery.map( this, fn, until );
		
		// 如果方法不是没有终止条件(Until)
		// 修正selector为第一个参数
		if ( name.slice( -5 ) !== "Until" ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			// 过滤matched中不符合selecotr的元素
			matched = jQuery.filter( selector, matched );
		}
		
		// this中如果有多个元素,那么遍历后的matched可能存在重复
		if ( this.length > 1 ) {
			// Remove duplicates
			if ( !guaranteedUnique[ name ] ) {
				jQuery.unique( matched );
			}

			// Reverse order for parents* and prev-derivatives
			// parent或pare的遍历matched应该反转,使matched顺序更符合逻辑
			if ( rparentsprev.test( name ) ) {
				matched.reverse();
			}
		}
		// 返回以matched为元素的新的JQuery对象
		return this.pushStack( matched );
	};
});