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

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

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

jQuery.fn.find( selector )

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

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

if(typeofselector !== "string") {

self=this;returnthis.pushStack( jQuery( selector ).filter(function() {for( i = 0; i < len; i++) {if( jQuery.contains( self[ i ],this) ) {returntrue;

}

}

}) );

}

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

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

ret =[];for( i = 0; i < len; i++) {//第二个参数是表示contextjQuery.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;returnret;

jQuery.fn.closest( selectors, context )

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

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

代码中的处理步骤为

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

pos = rneedsContext.test( selectors ) ||typeofselectors !== "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;

}

}returnthis.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 ) {varret = jQuery.map(this, fn, until );//过滤...returnthis.pushStack( ret );

};

});

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

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

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

if( !runtil.test( name ) ) {

selector=until;

}

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

if( selector &&typeofselector === "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();

}

最后,返回包裹后的结果

returnthis.pushStack( ret );

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

//从当前元素elem指定的dir对应的节点开始一直查找dir,并将这些节点保存在matched中,直到循环终止。注意:结果中不包含elem节点dir:function( elem, dir, until ) {varmatched =[],

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];

}returnmatched;

},//获取节点n及其兄弟节点中非elem的节点集合rsibling:function( n, elem ) {varr =[];for( ; n; n =n.nextSibling ) {if( n.nodeType === 1 && n !==elem ) {

r.push( n );

}

}returnr;

}//找到当前元素cur的下一个dir为止functionsibling( cur, dir ) {do{

cur=cur[ dir ];

}while( cur && cur.nodeType !== 1);returncur;

}

View Code

jQuery.fn.add( selector, context )和jQuery.fn. addBack( selector )

add函数是向当前匹配元素中添加符合指定表达式的元素,并以jQuery对象的形式返回。add可以接收包括:选择器(字符串)、HTML内容(字符串)、DOM元素(Element)、jQuery对象。处理比较简单,直接上源码

add:function( selector, context ) {varset =typeofselector === "string" ?jQuery( selector, context ) :

jQuery.makeArray( selector&& selector.nodeType ?[ selector ] : selector ),//把selector表达式获取的结果集拼接到当前对象上all = jQuery.merge(this.get(), set );//返回新的拼接结果returnthis.pushStack( jQuery.unique(all) );

}

jQuery.fn.add和jQuery.fn.not相对应。jQuery.fn.not后面再说。

jQuery.fn.addBack将之前匹配的元素加入到当前匹配的元素中,并以新的jQuery对象的形式返回。

addBack:function( selector ) {returnthis.add( selector ==null?this.prevObject :this.prevObject.filter(selector)

);

}

jQuery.fn.andSelf= jQuery.fn.addBack;

jQuery.fn.not( selector )和jQuery.fn.filter( selector )

not:function( selector ) {returnthis.pushStack( winnow(this, selector,false) );

}

filter:function( selector ) {returnthis.pushStack( winnow(this, selector,true) );

},

not和filter都是操作本身的集合,not是过滤掉本身集合中满足过滤条件selector的项,留下其他项。而filter是留下满足过滤条件selector的项。

关键是function winnow( elements, qualifier, keep )函数。这个函数的功能是执行相同的过滤或者不过滤的功能。过滤条件qualifier有三种:函数、DOM节点、字符串。keep:true表示保留满足过滤条件的项,false表示保留不满足过滤条件的项。winnow的源码注释如下

//执行相同的过滤或者不过滤的功能functionwinnow( elements, qualifier, keep ) {//Can't pass null or undefined to indexOf inFirefox4//Set to 0 to skipstring checkqualifier = qualifier || 0;//如果过滤条件是函数,则通过过滤函数过滤if( jQuery.isFunction( qualifier ) ) {returnjQuery.grep(elements,function( elem, i ) {varretVal = !!qualifier.call( elem, i, elem );returnretVal ===keep;

});//如果过滤条件是DOM相关类型,通过比较节点是否相同来过滤}elseif( qualifier.nodeType ) {returnjQuery.grep(elements,function( elem ) {return( elem === qualifier ) ===keep;

});//如果过滤条件是字符串}elseif(typeofqualifier === "string") {//过滤出elements中的节点元素varfiltered = jQuery.grep(elements,function( elem ) {returnelem.nodeType === 1;

});//其中isSimple = /^.[^:#\[\.,]*$/if( isSimple.test( qualifier ) ) {returnjQuery.filter(qualifier, filtered, !keep);

}else{//查找filtered中满足筛选条件qualifier的节点qualifier =jQuery.filter( qualifier, filtered );

}

}//过滤出elements中满足过滤条件的元素returnjQuery.grep(elements,function( elem ) {return( jQuery.inArray( elem, qualifier ) >= 0 ) ===keep;

});

}

View Code

其中用到jQuery.grep,grep详解点击这里。

jQuery.filter( expr, elems, not )这个低级api专门用来处理jQuery.fn.filter中过滤条件为字符串的情况。

jQuery.filter:function( expr, elems, not ) {if( not ) {

expr= ":not(" + expr + ")";

}//其中matchesSelector和matches是Sizzle中的函数。matchesSelector是判断单个元素elem是否满足表达式expr,matches是查找元素集合elems中满足表达式expr的项returnelems.length === 1 ?jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :

jQuery.find.matches(expr, elems);

},

jQuery.fn.index( elem )

index函数实际上是一个多功能函数的集合。

第一个功能:不传递elem参数,则表示取当前jQuery对象(jQuery对象的第一个元素)在其所有同辈元素中的位置。

if( !elem ) {return(this[0] &&this[0].parentNode ) ?this.first().prevAll().length : -1;

}

第二个功能:如果参数为String类型则将其视作选择器,返回当前元素在选择器所匹配的元素中的索引位置。如果该选择器不匹配任何元素或者当前元素不在匹配到的元素内,则返回-1。

if(typeofelem === "string") {//在数组jQuery( elem )中搜索指定的值,并返回其索引值returnjQuery.inArray(this[0], jQuery( elem ) );

}

第三个功能:如果object为DOM元素或jQuery对象,则返回该元素(或该jQuery对象中的第一个元素)在当前jQuery对象所匹配的元素中的索引位置。

returnjQuery.inArray(elem.jquery ? elem[0] : elem,this);

其他的筛选处理就不分析了。看源码即可明白。

如果觉得本文不错,请点击右下方【推荐】!

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航