JQuery日记 5.11 Sizzle选择器(五)

时间:2014-05-11 22:41:15   收藏:0   阅读:459
//设置当前document和document对应的变量和方法
setDocument = Sizzle.setDocument = function( node ) {
	var hasCompare,
		//node为Element时返回node所属document
		//node为Document时返回node
		//node为空时返回window.document
		doc = node ? node.ownerDocument || node : preferredDoc,
		//document所属window
		parent = doc.defaultView;

	// If no document and documentElement is available, return
	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
		return document;
	}

	// Set our document
	//设置全局的document为当前doc
	document = doc;
	docElem = doc.documentElement;

	// Support tests
	documentIsHTML = !isXML( doc );

	// Support: IE>8
	// If iframe document is assigned to "document" variable and if iframe has been reloaded,
	// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
	// IE6-8 do not support the defaultView property so parent will be undefined
	
	/* 
	 * 如果 iframe文档已经指定了document并且如果iframe重载
	 * 当访问document变量时,IE将抛出"permission denied"错误
	 * IE6-8不支持defaultView所以parent变量为undefined
	 */
	
	//所以要在unload的时候重新setDocument()
	//这个判断说明当前代码在frame中 
	if ( parent && parent !== parent.top ) {
		// IE11 does not have attachEvent, so all must suffer
		//frame卸载时重新设置document
		if ( parent.addEventListener ) {
			parent.addEventListener( "unload", function() {
				//未传入参数document=window.document
				setDocument();
			}, false );
		} else if ( parent.attachEvent ) {
			parent.attachEvent( "onunload", function() {
				setDocument();
			});
		}
	}
	
	//一些能力检查,添加到support中
	/* Attributes
	---------------------------------------------------------------------- */

	// Support: IE<8
	// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
	// IE8以下div.getAttribute("className")会得到class
	support.attributes = assert(function( div ) {
		div.className = "i";
		return !div.getAttribute("className");
	});

	/* getElement(s)By*
	---------------------------------------------------------------------- */

	// Check if getElementsByTagName("*") returns only elements
	//检查getElementsByTagName是否只返回Element元素
	support.getElementsByTagName = assert(function( div ) {
		div.appendChild( doc.createComment("") );
		return !div.getElementsByTagName("*").length;
	});

	// Check if getElementsByClassName can be trusted
	//检查getElementsByClassName是否能正确处理多class的情况
	support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
		div.innerHTML = "<div class=‘a‘></div><div class=‘a i‘></div>";

		// Support: Safari<4
		// Catch class over-caching
		div.firstChild.className = "i";
		// Support: Opera<10
		// Catch gEBCN failure to find non-leading classes
		return div.getElementsByClassName("i").length === 2;
	});

	// Support: IE<10
	// Check if getElementById returns elements by name
	// The broken getElementById methods don‘t pick up programatically-set names,
	// so use a roundabout getElementsByName test
	
	//检查是否getElementById会根据name返回元素
	support.getById = assert(function( div ) {
		docElem.appendChild( div ).id = expando;
		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
	});

	// ID find and filter
	if ( support.getById ) {
		Expr.find["ID"] = function( id, context ) {
			if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
				var m = context.getElementById( id );
				// Check parentNode to catch when Blackberry 4.6 returns
				// nodes that are no longer in the document #6963
				return m && m.parentNode ? [m] : [];
			}
		};
		Expr.filter["ID"] = function( id ) {
			//将转义字符转回字符串
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				return elem.getAttribute("id") === attrId;
			};
		};
	} else {
		// Support: IE6/7
		// getElementById is not reliable as a find shortcut
		//IE6,7的getElementById因为会根据name返回元素
		//所以是不能用原生getElementById方法获取元素的
		//所以删除
		delete Expr.find["ID"];

		Expr.filter["ID"] =  function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
				return node && node.value === attrId;
			};
		};
	}

	// Tag
	//getElementsByTagName是否只返回Element元素
	Expr.find["TAG"] = support.getElementsByTagName ?
		function( tag, context ) {
			if ( typeof context.getElementsByTagName !== strundefined ) {
				return context.getElementsByTagName( tag );
			}
		} :
		function( tag, context ) {
			var elem,
				tmp = [],
				i = 0,
				results = context.getElementsByTagName( tag );

			// Filter out possible comments
			if ( tag === "*" ) {
				while ( (elem = results[i++]) ) {
					if ( elem.nodeType === 1 ) {
						tmp.push( elem );
					}
				}

				return tmp;
			}
			return results;
		};

	// Class
	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
		if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
			return context.getElementsByClassName( className );
		}
	};

	/* QSA/matchesSelector
	---------------------------------------------------------------------- */

	// QSA and matchesSelector support

	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
	rbuggyMatches = [];

	// qSa(:focus) reports false when true (Chrome 21)
	// We allow this because of a bug in IE8/9 that throws an error
	// whenever `document.activeElement` is accessed on an iframe
	// So, we allow :focus to pass through QSA all the time to avoid the IE error
	// See http://bugs.jquery.com/ticket/13378
	rbuggyQSA = [];

	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
		// Build QSA regex
		// Regex strategy adopted from Diego Perini
		assert(function( div ) {
			// Select is set to empty string on purpose
			// This is to test IE‘s treatment of not explicitly
			// setting a boolean content attribute,
			// since its presence should be enough
			// http://bugs.jquery.com/ticket/12359
			div.innerHTML = "<select t=‘‘><option selected=‘‘></option></select>";

			// Support: IE8, Opera 10-12
			// Nothing should be selected when empty strings follow ^= or $= or *=
			if ( div.querySelectorAll("[t^=‘‘]").length ) {
				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:‘‘|\"\")" );
			}

			// Support: IE8
			// Boolean attributes and "value" are not treated correctly
			if ( !div.querySelectorAll("[selected]").length ) {
				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
			}

			// Webkit/Opera - :checked should return selected option elements
			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			// IE8 throws error here and will not see later tests
			if ( !div.querySelectorAll(":checked").length ) {
				rbuggyQSA.push(":checked");
			}
		});

		assert(function( div ) {
			// Support: Windows 8 Native Apps
			// The type and name attributes are restricted during .innerHTML assignment
			var input = doc.createElement("input");
			input.setAttribute( "type", "hidden" );
			div.appendChild( input ).setAttribute( "name", "D" );

			// Support: IE8
			// Enforce case-sensitivity of name attribute
			if ( div.querySelectorAll("[name=d]").length ) {
				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
			}

			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
			// IE8 throws error here and will not see later tests
			if ( !div.querySelectorAll(":enabled").length ) {
				rbuggyQSA.push( ":enabled", ":disabled" );
			}

			// Opera 10-11 does not throw on post-comma invalid pseudos
			div.querySelectorAll("*,:x");
			rbuggyQSA.push(",.*:");
		});
	}

	if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
		docElem.mozMatchesSelector ||
		docElem.oMatchesSelector ||
		docElem.msMatchesSelector) )) ) {

		assert(function( div ) {
			// Check to see if it‘s possible to do matchesSelector
			// on a disconnected node (IE 9)
			support.disconnectedMatch = matches.call( div, "div" );

			// This should fail with an exception
			// Gecko does not error, returns false instead
			matches.call( div, "[s!=‘‘]:x" );
			rbuggyMatches.push( "!=", pseudos );
		});
	}

	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );

	/* Contains
	---------------------------------------------------------------------- */
	hasCompare = rnative.test( docElem.compareDocumentPosition );

	// Element contains another
	// Purposefully does not implement inclusive descendent
	// As in, an element does not contain itself
	// 当节点contains自己时,返回true
	contains = hasCompare || rnative.test( docElem.contains ) ?
		function( a, b ) {
			//a是Document,adown为HtmlElement其他为a
			var adown = a.nodeType === 9 ? a.documentElement : a,
				//bup是b节点的父节点
				bup = b && b.parentNode;
			//(1)如果a是b的父节点,快速返回true
			//(2)如果b有父节点并且父节点是Element
			//	 a包含b的父节点返回true
			return a === bup || !!( bup && bup.nodeType === 1 && (
				adown.contains ?
					//contains的是bup而是b是为了避免contains自己时返回true
					adown.contains( bup ) :
					//为什么要&16,请看compareDocumentPosition的返回值
					/*  000000         0              元素一致
						000001         1              节点在不同的文档(或者一个在文档之外)
						000010         2              节点 B 在节点 A 之前
						000100         4              节点 A 在节点 B 之前
						001000         8              节点 B 包含节点 A
						010000         16             节点 A 包含节点 B
						100000         32             浏览器的私有使用 */
					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
			));
		} :
		//没有原生方法时迭代判断
		function( a, b ) {
			if ( b ) {
				//b的某个祖先节点===a说明a包含b
				while ( (b = b.parentNode) ) {
					if ( b === a ) {
						return true;
					}
				}
			}
			return false;
		};

	/* Sorting
	---------------------------------------------------------------------- */

	// Document order sorting
	sortOrder = hasCompare ?
	function( a, b ) {

		// Flag for duplicate removal
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		// Sort on method existence if only one input has compareDocumentPosition
		// 如果只有一个元素拥有排序方法.
		// a节点有排序方法返回-1,b节点有排序方法返回1
		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
		if ( compare ) {
			return compare;
		}

		// Calculate position if both inputs belong to the same document
		// 如果两个元素属于一个文档计算位置
		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
			a.compareDocumentPosition( b ) :
			// Otherwise we know they are disconnected
			1;

		// Disconnected nodes
		// 如果节点不再同一文档 或者 不支持分离排序并且a,b不再同一文档
		if ( compare & 1 ||
			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {

			// Choose the first element that is related to our preferred document
			// a节点包含在当前document返回-1
			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
				return -1;
			}
			// b节点包含在当前doucment返回1
			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
				return 1;
			}

			// Maintain original order
			// 保持原有顺序
			return sortInput ?
				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
				0;
		}
		//compare 
		//a在b之前返回-1,否则返回1
		return compare & 4 ? -1 : 1;
	} :
	function( a, b ) {
		// Exit early if the nodes are identical
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		var cur,
			i = 0,
			aup = a.parentNode,
			bup = b.parentNode,
			ap = [ a ],
			bp = [ b ];

		// Parentless nodes are either documents or disconnected
		//没有父亲节点说明可能是document或者以不再DOM树中的节点
		if ( !aup || !bup ) {
			//如果a是document说明a在前返回-1
			//如果b是document说明b在前返回1
			//否则如果a有父节点说明b是disconnected返回-1
			//否则b有父节点a是disconnected返回1
			//如果a、b都是disconnected,使用indexOf方法
			return a === doc ? -1 :
				b === doc ? 1 :
				aup ? -1 :
				bup ? 1 :
				sortInput ?
				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
				0;

		// If the nodes are siblings, we can do a quick check
		// 父亲是一个,使用siblingCheck(a,b)方法快速检查
		} else if ( aup === bup ) {
			return siblingCheck( a, b );
		}

		// Otherwise we need full lists of their ancestors for comparison
		// 否则需要遍历整个祖先
		cur = a;
		while ( (cur = cur.parentNode) ) {
			//将a的所有的祖先入栈
			ap.unshift( cur );
		}
		cur = b;
		while ( (cur = cur.parentNode) ) {
			//将b的所有的祖先入栈
			bp.unshift( cur );
		}

		// Walk down the tree looking for a discrepancy
		// 如果同层的祖先是一个
		while ( ap[i] === bp[i] ) {
			i++;
		}

		return i ?
			// Do a sibling check if the nodes have a common ancestor
			// 比较a,b的同级一个祖先之下的两个兄弟节点的位置
			siblingCheck( ap[i], bp[i] ) :

			// Otherwise nodes in our document sort first
			ap[i] === preferredDoc ? -1 :
			bp[i] === preferredDoc ? 1 :
			0;
	};
	//返回document
	return doc;
};

JQuery日记 5.11 Sizzle选择器(五),布布扣,bubuko.com

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!