首页 > 网站 > WEB开发 > 正文

jQuery-1.9.1源码分析系列(十二)筛选操作

2024-04-27 15:02:57
字体:
来源:转载
供稿:网友

  在前面分析的时候也分析了部分筛选操作(详见),我们接着分析,把主要的几个分析一下。

 

jQuery.fn.find( selector )

  find接受一个参数表达式selector:选择器(字符串)、DOM元素(Element)、jQuery对象。分两种情况处理:

  第一种,如果传入的参数是非字符串,则先通过jQuery选择器将selector查找出来,然后过滤出包含于当前jQuery对象所匹配的元素的节点。

if ( typeof selector !== "string" ) {    self = this;    return this.pushStack( jQuery( selector ).filter(function() {        for ( i = 0; i < len; i++ ) {            if ( jQuery.contains( self[ i ], this ) ) {                return true;            }        }    }) );}

  可以看出过滤条件中jQuery.contains( self[ i ], this )是关键,该函数使用的是Sizzle选择器中的函数,在Sizzle引擎中有分析,详情点击

  第二种,如果选择器是字符串,调用jQuery.find (= Sizzle)直接处理

ret = [];for ( i = 0; i < len; i++ ) {    //第二个参数是表示context    jQuery.find( selector, this[ i ], ret );}//$( selector, context )变成$( context ).find( selector ),需要去重和pushStackret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;return ret;

  

jQuery.fn.closest( selectors, context )

  第二个参数是可选的。函数用于从当前匹配元素开始,逐级向上级选取符合指定表达式的第一个元素,并以jQuery对象的形式返回。

  这里的表达式包括:选择器(字符串)、DOM元素(Element)、jQuery对象。

  代码中的处理步骤为

  1.根据传递的参数先查询出结果保存在pos中

pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?jQuery( selectors, context || this.context ) :0;

  2.遍历当前jQuery对象的每一个元素,从这个元素开始,逐级向上级选取符合指定表达式的第一个祖先元素

for ( ; i < l; i++ ) {    cur = this[i];    while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {        if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {            ret.push( cur );            break;        }        cur = cur.parentNode;    }}return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );

  parents() 和 .closest() 方法类似,它们都沿 DOM 树向上遍历。但区别也很大closest找到第一个符合条件就截止,parents是找到所有符合条件的集合。

 

jQuery.fn. parent/ parents/ parentsUntil/ next/ PRev/ nextAll/ prevAll/ nextUntil/ prevUntil/ siblings/ children/ contents详解

  以上几组筛选被放在一起处理,源码如下

jQuery.each({        parent: function( elem ) {…},        parents: function( elem ) {…},        parentsUntil: function( elem, i, until ) {…},        next: function( elem ) {…},        prev: function( elem ) {…},        nextAll: function( elem ) {…},        prevAll: function( elem ) {…},        nextUntil: function( elem, i, until ) {…},        prevUntil: function( elem, i, until ) {…},        siblings: function( elem ) {…},        children: function( elem ) {…},        contents: function( elem ) {…}    }, function( name, fn ) {        jQuery.fn[ name ] = function( until, selector ) {            var ret = jQuery.map( this, fn, until );            //过滤            ...            return this.pushStack( ret );        };    });

  可以看出,这几个筛选步骤一致。都是先通过map函数把当前jQuery对象每个匹配的元素代入相应的匹配函数(fn)中获取出结果然后在进行后续的过滤。

 

  我们先看一下后面的过滤(已经通过jQuery.map( this, fn, until )获取到了备选种子ret)

  首先,并不是所有的筛选函数都有until这个参数,只有以Until结尾的几个筛选才需要这个参数,其他的筛选只有selector这个参数。

if ( !runtil.test( name ) ) {    selector = until;}

  其次,如果有选择器,则通过选择器过滤一下先前查找结果ret

if ( selector && typeof selector === "string" ) {    ret = jQuery.filter( selector, ret );}

  然后,guaranteedUnique里面的几种筛选条件(children/contents/next/prev)在当前jQuery对象所匹配的元素个数有多个的时候,通过每个匹配元素获取到的结果保存在结果集ret中,且不需要去重。其他筛选是要去重的。点击查看jQuery.unique方法详解

ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;

  另外,还需要处理的特殊情况是: 如果当前jQuery对象所匹配的元素有多个,则使用parents /prevUntil /prevAll这三种筛选的结果需要倒序排列。需要倒序的原因:jQuery.unique使用的是Sizzle引擎中的排序函数Sizzle .uniqueSort,这个排序函数会根据文档最顶层对象到最底层的方式排列

if ( this.length > 1 && rparentsprev.test( name ) ) {    ret = ret.reverse();}

 

  最后,返回包裹后的结果

return this.pushStack( ret );

  

  上面说了主题的框架结构,下面说一下这一组筛选器匹配函数里面用到的两个函数jQuery.dir和jQuery. sibling,直接上源码

//从当前元素elem指定的dir对应的节点开始一直查找dir,并将这些节点保存在matched中,直到循环终止。注意:结果中不包含elem节点dir: function( elem, dir, until ) {    var matched = [],    cur = elem[ dir ];    while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {        if ( cur.nodeType === 1 ) {            matched.push( cur );        }        cur = cur[dir];    }    return matched;},//获取节点n及其兄弟节点中非elem的节点集合rsibling: function( n, elem ) {    var r = [];    for ( ; n; n = n.nextSibling ) {        if ( n.nodeType === 1 && n !== elem ) {            r.push( n );        }    }    return r;}//找到当前元素cur的下一个dir为止function sibling( cur, dir ) {        do {            cur = cur[ dir ];        } while ( cur && cur.nodeType !== 1 );        return cur;    }
View Code
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表