jQuery源码分析之contains函数

来源:互联网 发布:新能源汽车销售数据 编辑:程序博客网 时间:2024/05/05 11:16

jQuery,.contains底层调用的方法来自于JS的contains方法和compareDocumentPosition方法

测试例子:

//打印truealert(document.getElementById("sec").ownerDocument===document);//打印[object HTMLDocument]alert(document.getElementById("sec").ownerDocument);

测试代码2:

//打印truealert(document.getElementById("sec").ownerDocument===document);//打印false,getElementsByTagName("body")[0]则返回truealert(document.getElementsByTagName("body").ownerDocument===document);//打印truealert(document.getElementsByTagName("body")[0].ownerDocument===document);//打印undefined,因为是NodeList,不是Element元素alert(document.getElementsByTagName("body").ownerDocument);//不是Element对象,直接返回undefinedalert(document.getElementsByTagName("p").ownerDocument);//打印[object Window]alert(document.defaultView);//打印undefinedalert(document.getElementById("sec").defaultView);//打印undefined,document对象才有defaultView和documentElementalert(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,打印undefinedalert(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是否相等,如果相等就返回truefunction( 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

0 0
原创粉丝点击