深入学习jquery源码之has()和closest()

深入学习jquery源码之has()和closest()

has(expr|ele)

概述

保留包含特定后代的元素,去掉那些不含有指定后代的元素。

.has()方法将会从给定的jQuery对象中重新创建一组匹配的对象。提供的选择器会一一测试原先那些对象的后代,含有匹配后代的对象将得以保留。

参数

expr String

一个选择器字符串。

element DOMElement

一个DOM元素

给含有ul的li加上背景色

<ul>
  <li>list item 1</li>
  <li>list item 2
    <ul>
      <li>list item 2-a</li>
      <li>list item 2-b</li>
    </ul>
  </li>
  <li>list item 3</li>
  <li>list item 4</li>
</ul>
$('li').has('ul').css('background-color', 'red');

closest(expr,[context]|object|element)

概述

jQuery 1.3新增。从元素本身开始,逐级向上级元素匹配,并返回最先匹配的元素。。

closest会首先检查当前元素是否匹配,如果匹配则直接返回元素本身。如果不匹配则向上查找父元素,一层一层往上,直到找到匹配选择器的元素。如果什么都没找到则返回一个空的jQuery对象。

closest和parents的主要区别是:1,前者从当前元素开始匹配寻找,后者从父元素开始匹配寻找;2,前者逐级向上查找,直到发现匹配的元素后就停止了,后者一直向上查找直到根元素,然后把这些元素放进一个临时集合中,再用给定的选择器表达式去过滤;3,前者返回0或1个元素,后者可能包含0个,1个,或者多个元素。

closest对于处理事件委托非常有用。

参数

expr String,Array

用以过滤元素的表达式。jQuery 1.4开始,也可以传递一个字符串数组,用于查找多个元素。

expr,[context] String

expr:用以过滤子元素的表达式

context:DOM元素在其中一个匹配的元素可以被发现。如果没有上下文在当时的情况下通过了jQuery设置将被使用。

jQuery object  object

一个用于匹配元素的jQuery对象

element DOMElement

一个用于匹配元素的DOM元素。

展示如何使用clostest查找多个元素

<ul><li></li><li></li></ul>
$("li:first").closest(["ul", "body"]);
[ul, body]

展示如何使用clostest来完成事件委托。

<ul>
    <li><b>Click me!</b></li>
    <li>You can also <b>Click me!</b></li>
</ul>
$(document).bind("click", function (e) {
    $(e.target).closest("li").toggleClass("hilight");
});

jquery源码

    jQuery = function (selector, context) {
            // The jQuery object is actually just the init constructor 'enhanced'
            // Need init if jQuery is called (just allow error to be thrown if not included)
            return new jQuery.fn.init(selector, context);
	}
	
	init = jQuery.fn.init = function (selector, context) {
	
	}
	
	    var rneedsContext = jQuery.expr.match.needsContext;
        var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
        var risSimple = /^.[^:#\[\.,]*$/;
		
	jQuery.filter = function (expr, elems, not) {
        var elem = elems[0];

        if (not) {
            expr = ":not(" + expr + ")";
        }

        return elems.length === 1 && elem.nodeType === 1 ?
            jQuery.find.matchesSelector(elem, expr) ? [elem] : [] :
            jQuery.find.matches(expr, jQuery.grep(elems, function (elem) {
                return elem.nodeType === 1;
            }));
    };
	
	  rnative = /^[^{]+\{\s*\[native \w/
	     hasCompare = rnative.test(docElem.compareDocumentPosition);

                // Element contains another
                // Purposefully does not implement inclusive descendent
                // As in, an element does not contain itself
         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 ?
                                adown.contains(bup) :
                                a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
                        ));
                    } :
                    function (a, b) {
                        if (b) {
                            while ((b = b.parentNode)) {
                                if (b === a) {
                                    return true;
                                }
                            }
                        }
                        return false;
         };
	
	
	jQuery.fn.extend({
        has: function (target) {
            var i,
                targets = jQuery(target, this),
                len = targets.length;

            return this.filter(function () {
                for (i = 0; i < len; i++) {
                    if (jQuery.contains(this, targets[i])) {
                        return true;
                    }
                }
            });
        },

        closest: function (selectors, context) {
            var cur,
                i = 0,
                l = this.length,
                matched = [],
                pos = rneedsContext.test(selectors) || typeof selectors !== "string" ?
                    jQuery(selectors, context || this.context) :
                    0;

            for (; i < l; i++) {
                for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) {
                    // Always skip document fragments
                    if (cur.nodeType < 11 && (pos ?
                        pos.index(cur) > -1 :

                        // Don't pass non-elements to Sizzle
                        cur.nodeType === 1 &&
                        jQuery.find.matchesSelector(cur, selectors))) {

                        matched.push(cur);
                        break;
                    }
                }
            }

            return this.pushStack(matched.length > 1 ? jQuery.unique(matched) : matched);
        }
    });

猜你喜欢

转载自blog.csdn.net/qq_35029061/article/details/85318843