jQuery,.contains底层调用的方法来自于JS的contains方法和compareDocumentPosition方法
测试例子:
//打印true alert(document.getElementById("sec").ownerDocument===document); //打印[object HTMLDocument] alert(document.getElementById("sec").ownerDocument);测试代码2:
//打印true alert(document.getElementById("sec").ownerDocument===document); //打印false,getElementsByTagName("body")[0]则返回true alert(document.getElementsByTagName("body").ownerDocument===document); //打印true alert(document.getElementsByTagName("body")[0].ownerDocument===document); //打印undefined,因为是NodeList,不是Element元素 alert(document.getElementsByTagName("body").ownerDocument); //不是Element对象,直接返回undefined alert(document.getElementsByTagName("p").ownerDocument); //打印[object Window] alert(document.defaultView); //打印undefined alert(document.getElementById("sec").defaultView); //打印undefined,document对象才有defaultView和documentElement alert(document.getElementById("sec").documentElement);
从这个例子中你要弄清楚,ownerDocument是Element元素的专利,而NodeList等没有ownerDocument属性;同时defaultView是document的专利,返回的是window对象。对于不同的浏览器可能用document.defaultView||document.parentWindow||window!
测试代码3:
//rnative = /^[^{]+\{\s*\[native \w/ //[^{]表示除了左大括号的任何字符 //var docElem = window.document.documentElement; //打印[object HTMLHtmlElement] //alert( window.document.documentElement); //alert( window.document.documentElement.compareDocumentPosition);打印function compareDocumentPosition(){[native code]} //alert( window.document.documentElement.contains);打印function contains(){[native code]}
从这个例子你应该明白,jQuery的contains判断是否有JS原生的contains和compareDocument方法用的是正则表达式的!
<div id="n1"> <p id="n2"> <span id="n3">CodePlayer</span> </p> </div> <p id="n4">专注于编程开发技术分享</p>
JS部分
//n1虽然包含span元素(n3),但变量span是NodeList对象,不是Element类型。 alert( $.contains(n1, $("span")) ); // false //NodeList的parentNode是undefined,打印undefined alert(span.parentNode); //jQuery对象也没有parentNode,parentNode是JS原生的属性 alert($("#n1").parentNode);contains方法的第二个参数必须是Element对象,而 不能是jQuery对象或者NodeList对象!
contains方法:
hasCompare = rnative.test( docElem.compareDocumentPosition ); // Element contains another // Purposefully does not implement inclusive descendent // As in, an element does not contain itself //contains函数 //如果正则表达式通过表示浏览器支持compareDocumentPosition,如果不支持那么继续判断JS原生的contains函数 contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { //如果a元素是document对象,那么获取documentElement,否则保存a对象即可 var adown = a.nodeType === 9 ? a.documentElement : a, //如果b不是空,那么获取b元素的parentNode对象 bup = b && b.parentNode; //(1)如果b元素的父元素是a元素,那么返回true,否则继续下一步判断 //(2)如果b的父元素存在,但是不是a元素,而且父元素已经是docmentElement也就是html元素,如:alert(document.getElementsByTagName("body")[0].parentNode.nodeType);返回1 //注意:这里必须要求b的parentNode是元素类型,NodeList等类型直接返回false,见上例子: return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? //如果contains存在,调用contains,也就是a包含了b元素的父亲 adown.contains( bup ) : //如果不存在contains方法,那么直接调用compareDocumentPosition方法就可以了! a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : //如果不存在compareDocumentPosition也不存在contains方法,那么直接取出b的parentNode //比较parentNode和a是否相等,如果相等就返回true function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; };
如果是具有原生的compareDocumentPosition或者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 ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16//验证被包含关系我们用&16! )); }
compareDocumentPosition还可以用于比较其它的关系:
上面的HTML,n4在n1后面
//n4在n1后面 var result=$('#n1')[0].compareDocumentPosition($('#n4')[0])&4; //打印4,所以n4在n1后面(前后是站在参数的角度上来说的,判断参数相对于调用者的位置) console.log(result);上面的HTML,判断n2包含n3
//n2包含n3 var result=$('#n3')[0].compareDocumentPosition($('#n2')[0])&8; //打印8,所以n2包含n3(前后是站在参数的角度上来说的,判断参数相对于调用者的位置) console.log(result);注意:compreDcoumentPositon站在参数的角度上来说的, 2表示参数居前,4表示参数居后,8表示参数包含,16表示参数被包含!
如果没有原生的方法的时候我们调用下面的逻辑
function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; };不管获取被包含节点的父节点,如果当前节点和父节点相同,那么我们返回true