zoukankan      html  css  js  c++  java
  • 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 );
            };
    
  • 相关阅读:
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
    团队作业-随堂小测(同学录)
    Alpha 冲刺 (5/10)
    LeetCode-1
    c++向量
    软件工程实践总结作业
    个人作业——软件产品案例分析
    个人技术博客Alpha----Android Studio学习
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1608569.html
Copyright © 2011-2022 走看看