Ruby's Louvre

每天学习一点点算法

导航

jQuery源码学习笔记七

在Sizzle中有许多有用的辅助方法,我们继续一个个看。其中涉及许多BUG的修正以及一些很少见的API。

//@author  司徒正美|なさみ|cheng http://www.cnblogs.com/rubylouvre/ All rights reserved
      var sortOrder;//比较两个元素在页面上的顺序,返回正数,0,负数
      //如果支持compareDocumentPosition方法,新锐的标准浏览器都支持
      //我在《javascript contains方法》一文中有详细介绍
      //http://www.cnblogs.com/rubylouvre/archive/2009/10/14/1583523.html
      if ( document.documentElement.compareDocumentPosition ) {
        sortOrder = function( a, b ) {
          //节点a 在节点b 之前,
          var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
          if ( ret === 0 ) {
            hasDuplicate = true;
          }
          return ret;
        };
        //用于IE
        //sourceIndex是指元素在NodeList中的位置
      } else if ( "sourceIndex" in document.documentElement ) {
        sortOrder = function( a, b ) {
          var ret = a.sourceIndex - b.sourceIndex;
          if ( ret === 0 ) {
            hasDuplicate = true;
          }
          return ret;
        };
        //用于旧式的标准游览器
      } else if ( document.createRange ) {
        sortOrder = function( a, b ) {
          var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
          aRange.selectNode(a);
          aRange.collapse(true);
          bRange.selectNode(b);
          bRange.collapse(true);
          //比较两个selection的位置
          //https://developer.mozilla.org/en/DOM/range.compareBoundaryPoints
          var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
          if ( ret === 0 ) {
            hasDuplicate = true;
          }
          return ret;
        };
      }

比较元素位置在IE还可以用uniqueNumber,都是自上至下分配数字。

下面对getElementById,getElementsByTagName,getElementsByClassName, querySelectorAll 进行调整。

//在getElementById(XXX)在IE中有bug,它会找第一个属性name或id等于XXX的元素,
//尤其是在表单元素中,它们通常都带有name属性
(function(){
	// We're going to inject a fake input element with a specified name
	var form = document.createElement("form"),
		id = "script" + (new Date).getTime();
	form.innerHTML = "<input name='" + id + "'/>";

	// Inject it into the root element, check its status, and remove it quickly
	var root = document.documentElement;
	root.insertBefore( form, root.firstChild );

	// The workaround has to do additional checks after a getElementById
	// Which slows things down for other browsers (hence the branching)
	if ( !!document.getElementById( id ) ) {
        //重载一下Expr.find.ID
		Expr.find.ID = function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
                //确定此元素是否显式为id赋值
				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" &&
                    m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
			}
		};

		Expr.filter.ID = function(elem, match){
             //确定此元素是否显式为id赋值
			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
			return elem.nodeType === 1 && node && node.nodeValue === match;
		};
	}

	root.removeChild( form );
})();

(function(){
	// Check to see if the browser returns only elements
	// when doing getElementsByTagName("*")

	// Create a fake element
	var div = document.createElement("div");
	div.appendChild( document.createComment("") );

	// Make sure no comments are found
	if ( div.getElementsByTagName("*").length > 0 ) {
        //重载Expr.find.TAG
		Expr.find.TAG = function(match, context){
			var results = context.getElementsByTagName(match[1]);

			// Filter out possible comments
            //返回其所有元素节点后代,组成纯数组
			if ( match[1] === "*" ) {
				var tmp = [];

				for ( var i = 0; results[i]; i++ ) {
					if ( results[i].nodeType === 1 ) {
						tmp.push( results[i] );
					}
				}

				results = tmp;
			}

			return results;
		};
	}

	// Check to see if an attribute returns normalized href attributes
    //处理href属性,如果第二个参数,IE返回的是绝对路径
	div.innerHTML = "<a href='#'></a>";
	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
			div.firstChild.getAttribute("href") !== "#" ) {
		Expr.attrHandle.href = function(elem){
			return elem.getAttribute("href", 2);
		};
	}
})();

if ( document.querySelectorAll ) (function(){
    //创建一个元素片段<div><p class='TEST'></p></div>
    //用querySelectorAll看看能否正确找到这个p元素
	var oldSizzle = Sizzle, div = document.createElement("div");
	div.innerHTML = "<p class='TEST'></p>";

	// Safari can't handle uppercase or unicode characters when
	// in quirks mode.
	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
		return;
	}
	//如果能,就用querySelectorAll重载整个Sizzle引擎,效率最高!!!
	Sizzle = function(query, context, extra, seed){
		context = context || document;

		// Only use querySelectorAll on non-XML documents
		// (ID selectors don't work in non-HTML documents)
		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
			try {
				return makeArray( context.querySelectorAll(query), extra );
			} catch(e){}
		}
		
		return oldSizzle(query, context, extra, seed);
	};

	Sizzle.find = oldSizzle.find;
	Sizzle.filter = oldSizzle.filter;
	Sizzle.selectors = oldSizzle.selectors;
	Sizzle.matches = oldSizzle.matches;
})();

if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
     //创建一个元素片段<div><div class='test e'></div><div class='test'></div></div>
    //用getElementsByClassName看看能否正确找到这两个div元素
	var div = document.createElement("div");
	div.innerHTML = "<div class='test e'></div><div class='test'></div>";

	// Opera can't find a second classname (in 9.6)
	if ( div.getElementsByClassName("e").length === 0 )
		return;

	// Safari caches class attributes, doesn't catch changes (in 3.2)
	div.lastChild.className = "e";

	if ( div.getElementsByClassName("e").length === 1 )
		return;
//重新调整与CLASS有关的逻辑
	Expr.order.splice(1, 0, "CLASS");
	Expr.find.CLASS = function(match, context, isXML) {
		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
			return context.getElementsByClassName(match[1]);
		}
	};
})();
//这东西用于后代选择器与兄长选择器,取得某范围中所有元素,并且防止重复取得
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	var sibDir = dir == "previousSibling" && !isXML;
    //checkSet为元素集合,doneName为数字
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			if ( sibDir && elem.nodeType === 1 ){
				elem.sizcache = doneName;//设置一标记,以后有与它值相等的不重复取
				elem.sizset = i;
			}
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {//比较是否相等
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 && !isXML ){
					elem.sizcache = doneName;
					elem.sizset = i;
				}

				if ( elem.nodeName === cur ) {
					match = elem;
					break;
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}
//和上面功能差不多,不知是否出于兼容以前版本的需要……
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	var sibDir = dir == "previousSibling" && !isXML;
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			if ( sibDir && elem.nodeType === 1 ) {
				elem.sizcache = doneName;
				elem.sizset = i;
			}
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 ) {
					if ( !isXML ) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}
					if ( typeof cur !== "string" ) {
						if ( elem === cur ) {
							match = true;
							break;
						}

					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
						match = elem;
						break;
					}
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}
        //判断一个元素是否包含另一个元素
        //http://www.cnblogs.com/rubylouvre/archive/2009/10/14/1583523.html
        var contains = document.compareDocumentPosition ?  function(a, b){
            return a.compareDocumentPosition(b) & 16;
        } : function(a, b){
            return a !== b && (a.contains ? a.contains(b) : true);
        };
        //判断是否为XML
        var isXML = function(elem){
            return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
            !!elem.ownerDocument && isXML( elem.ownerDocument );
        };
        //主要是处理结构伪类中的子元素过滤器
        var posProcess = function(selector, context){
            var tmpSet = [], later = "", match,
            root = context.nodeType ? [context] : context;

            // Position selectors must be done after the filter
            // And so must :not(positional) so we move all PSEUDOs to the end
            while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
                later += match[0];
                selector = selector.replace( Expr.match.PSEUDO, "" );
            }
            //如果不是在亲子中选择,就是在它的所有后代中选择“*”
            selector = Expr.relative[selector] ? selector + "*" : selector;
            //回调Sizzle
            for ( var i = 0, l = root.length; i < l; i++ ) {
                Sizzle( selector, root[i], tmpSet );
            }

            return Sizzle.filter( later, tmpSet );
        };

posted on 2009-11-23 15:18  司徒正美  阅读(2697)  评论(10编辑  收藏  举报