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