在各种聚会,毕设任务后。。。我又回来了!!!
继续分析jquery中的sizzle源码
在Sizzle主函数以后,先是一些列的零散函数,为后面support检测,事件代理提供先期方法。这些函数内容比较简单,就直接分析掉了:
// 为function作标记 function markFunction( fn ) { fn[ expando ] = true; return fn; } /** * 用一个div元素来做一些检测 */ function assert( fn ) { var div = document.createElement("div"); try { return !!fn( div ); } catch (e) { return false; } finally { // 将div移除 if ( div.parentNode ) { div.parentNode.removeChild( div ); } // 释放缓存 div = null; } } // 给所有的attrs添加相同的handler function addHandle( attrs, handler ) { var arr = attrs.split("|"), i = attrs.length; while ( i-- ) { Expr.attrHandle[ arr[i] ] = handler; } } /** * 检测两个元素的顺序 * 返回小于0 则a在b前, 大于 0 则a在b后 */ function siblingCheck( a, b ) { var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); // 如果可以的话,就用IE的sourceIndex if ( diff ) { return diff; } // 检测b是否在a后面 if ( cur ) { while ( (cur = cur.nextSibling) ) { if ( cur === b ) { return -1; } } } return a ? 1 : -1; } /** *会返回一个函数,用于检测input的type */ function createInputPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === type; }; } /** * 返回一个函数,用于检测input或buttong的type */ function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && elem.type === type; }; } /** * 返回一个函数,用于检测元素的位置 */ function createPositionalPseudo( fn ) { return markFunction(function( argument ) { argument = +argument; return markFunction(function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // 找到特定位置的元素 while ( i-- ) { if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }); }); }
接下来就是setDocument了,它根据现有的document来设置,并在函数体中做了很多关于support的检测,它会返回当前的document
看了很久发现要写好多好多东西,这个函数居然有400行,容我慢慢注释下,后面会补上
=========================================分割线========================================
好,下面上源码,和以前一样,里面调用的函数在下面会讲到,其中rbuggyMatches是支撑matches的正则串,rbuggyQSA是支撑qsa的正则串
setDocument = Sizzle.setDocument = function( node ) { var hasCompare, // 如果没有node,就直接去preferredDoc doc = node ? node.ownerDocument || node : preferredDoc, parent = doc.defaultView; // 如果没有document或者documentElement不可访问,就直接返回 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } // 设置document document = doc; docElem = doc.documentElement; // 开始关于support的检测 documentIsHTML = !isXML( doc ); // Support: IE>8 // 在iframe中,如果需要访问到document,在iframe重载之后 // 当要访问document时,IE会报出"permission denied"错误 // IE6-8 d不支持defaultView,所以parent会未定义 if ( parent && parent !== parent.top ) { // IE11 不支持attachEvent。。。。 if ( parent.addEventListener ) { parent.addEventListener( "unload", function() { setDocument(); }, false ); } else if ( parent.attachEvent ) { parent.attachEvent( "onunload", function() { setDocument(); }); } } /* 各种属性 ---------------------------------------------------------------------- */ // Support: IE<8 // 检测getAttribute是否真的返回相应的attribute而不是属性 support.attributes = assert(function( div ) { div.className = "i"; return !div.getAttribute("className"); }); /* getElement(s)By* ---------------------------------------------------------------------- */ // 检测 getElementsByTagName("*") 是否只返回元素 support.getElementsByTagName = assert(function( div ) { div.appendChild( doc.createComment("") ); return !div.getElementsByTagName("*").length; }); // 检测是否getElementsByClassName是否工作正常 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { div.innerHTML = "<div class='a'></div><div class='a i'></div>"; div.firstChild.className = "i"; // Support: Opera<10 // 判断是否可以得到非开头的class return div.getElementsByClassName("i").length === 2; }); // Support: IE<10 // 检测getElementById 返回的是不是 elements by 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 ); // 检测是否返回了已经删除了的元素 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并不可靠 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 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 ); // 将不是element的元素剔除 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) 在应该是true时会返回false (IE9/Opera 11.5) rbuggyMatches = []; // qSa(:focus) 在应该是true时会返回false (Chrome 21) rbuggyQSA = []; if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { assert(function( div ) { // Select 被有意的设置为空 // 这是为了检测IE的行为 div.innerHTML = "<select t=''><option selected=''></option></select>"; // Support: IE8, Opera 10-12 // 在^= 或 $= 或 *=之后如果字符串为空,应该无元素返回 if ( div.querySelectorAll("[t^='']").length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|"")" ); } // Support: IE8 // bool属性并没有被正确的使用 if ( !div.querySelectorAll("[selected]").length ) { rbuggyQSA.push( "\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Webkit/Opera - :checked 应该返回被选中的元素 if ( !div.querySelectorAll(":checked").length ) { rbuggyQSA.push(":checked"); } }); assert(function( div ) { // Support: Windows 8 Native Apps // 在设置innerHTML时,type和name的设置会被限制 var input = doc.createElement("input"); input.setAttribute( "type", "hidden" ); div.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // 增强对name的敏感程度 if ( div.querySelectorAll("[name=d]").length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled ,hidden 元素 (hidden元素仍然是enable状态) if ( !div.querySelectorAll(":enabled").length ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Opera 10-11 在不正确的查询下不会报错 div.querySelectorAll("*,:x"); rbuggyQSA.push(",.*:"); }); } if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector) )) ) { assert(function( div ) { // 首先尝试下matchesSelector是否能够正常运行 support.disconnectedMatch = matches.call( div, "div" ); // 这个应该会报错 // 在Gecko无错误,只会返回一个false 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 ); // 元素包含 // 这个函数返回的值里,一个元素不会被自己包含 contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode; return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? //直接用原生的contains adown.contains( bup ) : //或者使用compareDocumentPosition,关于&16的问题可以看下 //关于这个compareDocumentPosition函数的返回值 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : function( a, b ) { if ( b ) { // 循环取b的parentNode,取到顶后会返回false while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; }; /* 排序 ---------------------------------------------------------------------- */ // Document order sorting sortOrder = hasCompare ? function( a, b ) { // Flag for duplicate removal if ( a === b ) { hasDuplicate = true; return 0; } // 在a,b中只有一个有compareDocumentPosition的情况下运行,直接返回 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; if ( compare ) { return compare; } // 在他们都属于一个文档下,调用compareDocumentPosition compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // 否则他们无关 1; // 对于无关的两个node if ( compare & 1 || // support.sortDetached对于Webkit<537.32 - Safari 6.0.3/Chrome 25的bug检测 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { // 选择第一个和现在文档相关的元素 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { return -1; } if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { return 1; } // 用原有的order,这个还有点迷惑,sortInput貌似只在一个函数里用过,而且是立即销毁的 return sortInput ? ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 0; } return compare & 4 ? -1 : 1; } : function( a, b ) { // 元素相同就返回 if ( a === b ) { hasDuplicate = true; return 0; } var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [ a ], bp = [ b ]; // 如果无parent,那么不是document,就是无关的 if ( !aup || !bup ) { return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : sortInput ? ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 0; // 如果两个是sibling关系的,就直接调用siblingCheck } else if ( aup === bup ) { return siblingCheck( a, b ); } // 否则就需要完全列出它们的祖先元素 cur = a; while ( (cur = cur.parentNode) ) { ap.unshift( cur ); } cur = b; while ( (cur = cur.parentNode) ) { bp.unshift( cur ); } // 向下遍历直到找出分支 while ( ap[i] === bp[i] ) { i++; } return i ? // 看下是否有正常的祖先元素 siblingCheck( ap[i], bp[i] ) : // 否则节点在document外?? ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0; }; return doc; };
接下来是其中的几个小函数调用,首先是support.sortDetached:
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 // 侦测node对于follow混淆 support.sortDetached = assert(function( div1 ) { // 应该返回1,但是返回的是4 return div1.compareDocumentPosition( document.createElement("div") ) & 1; });
然后是siblingCheck,这个函数在这篇文章的前面分析过~
这篇就到这吧,回去搞我的毕业设计了。。。。。