Home  >  Article  >  Web Front-end  >  Jquery 1.9.1 source code analysis series filtering operations

Jquery 1.9.1 source code analysis series filtering operations

PHPz
PHPzOriginal
2016-05-16 15:28:171078browse

Without further ado, let’s get straight to the topic.

jQuery.fn.find( selector )

find accepts a parameter expression selector: selector (string), DOM element (Element), jQuery object. It is handled in two situations:

The first one, if the incoming parameter is a non-string, first find the selector through the jQuery selector, and then filter out the matching items contained in the current jQuery object. The node of the element.

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;
   }
  }
 }) );
}

You can see that jQuery.contains( self[ i ], this ) is the key in the filter condition. This function uses the function in the Sizzle selector. There is analysis in the Sizzle engine, click for details.

Second, if the selector is a string, call jQuery.find (= Sizzle) to process it directly

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

The second parameter is optional. The function is used to select the first element that matches the specified expression, starting from the current matching element, and returning it in the form of a jQuery object.

The expressions here include: selector (string), DOM element (Element), and jQuery object.

The processing steps in the code are

1. First query the results according to the passed parameters and save them in pos.

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

2. Traverse each element of the current jQuery object. Starting from this element, select the first ancestor element that matches the specified expression step by step.

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

The parents() and .closest() methods are similar in that they both traverse up the DOM tree. But the difference is also very big: closest finds the first one that meets the conditions and ends it; parents finds all the sets that meet the conditions.

jQuery.fn. parent/ parents/ parentsUntil/ next/ prev/ nextAll/ prevAll/ nextUntil/ prevUntil/ siblings/ children/ contents detailed explanation

The above groups of filters are processed together, the source code is as follows

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 );
  };
 });

It can be seen that these filtering steps are consistent. Each matching element of the current jQuery object is first substituted into the corresponding matching function (fn) through the map function to obtain the result, and then subsequent filtering is performed.

Let’s take a look at the subsequent filtering first (the alternative seed ret has been obtained through jQuery.map( this, fn, until ))
First of all, not all filtering functions have until This parameter is only required for several filters ending with Until. Other filters only have the selector parameter.

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

Secondly, if there is a selector, filter the previous search results through the selector ret

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

Then, guaranteedeedUnique There are several filtering conditions (children/contents/next/prev). When the number of elements matched by the current jQuery object is multiple, the results obtained through each matching element are saved in the result set ret, and no need to Remove weight. Other screenings need to be done. Click to view the detailed explanation of the jQuery.unique method

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

In addition, the special cases that need to be handled are: If there are multiple elements matched by the current jQuery object, use parents /prevUntil / prevAll The results of these three filters need to be sorted in reverse order. The reason for the need for reverse order: jQuery.unique uses the sorting function Sizzle .uniqueSort in the Sizzle engine. This sorting function arranges objects from the topmost object to the bottommost object in the document.

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

Finally, return the packaged result

return this.pushStack( ret ); 

The above mentioned the framework structure of the theme, let’s talk about this For the two functions jQuery.dir and jQuery.sibling used in the group filter matching function, go directly to the source code
// Search dir starting from the node corresponding to dir specified by the current element elem, and save these nodes in matched in until the loop terminates. Note: The result does not include elem nodes

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的节点集合r
sibling: 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;
 } 
jQuery.fn.add( selector, context )和jQuery.fn. addBack( selector )

The add function adds a specified expression to the current matching element element of the formula and returned as a jQuery object. add can receive: selector (string), HTML content (string), DOM element (Element), and jQuery object. The processing is relatively simple, just go to the source code

add: function( selector, context ) {
 var set = typeof selector === "string" ?
   jQuery( selector, context ) :
   jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
  //把selector表达式获取的结果集拼接到当前对象上
  all = jQuery.merge( this.get(), set );
 //返回新的拼接结果
 return this.pushStack( jQuery.unique(all) );
}
  jQuery.fn.add和jQuery.fn.not相对应。jQuery.fn.not后面再说。
  jQuery.fn.addBack将之前匹配的元素加入到当前匹配的元素中,并以新的jQuery对象的形式返回。
addBack: function( selector ) {
 return this.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 ) {
 return this.pushStack( winnow(this, selector, false) );
}
filter: function( selector ) {
 return this.pushStack( winnow(this, selector, true) );
},

not and filter are both collections of the operation itself, not is to filter out the items in the collection itself that meet the filtering condition selector, leaving other items . The filter is to leave items that meet the filter condition selector.

The key is the function winnow(elements, qualifier, keep) function. The function of this function is to perform the same filtering or non-filtering function. There are three types of filter condition qualifiers: functions, DOM nodes, and strings. keep: true means to keep items that meet the filter conditions, false means to keep items that do not meet the filter conditions.

The source code comments of winnow are as follows

//执行相同的过滤或者不过滤的功能
function winnow( elements, qualifier, keep ) {
 // Can&#39;t pass null or undefined to indexOf in Firefox 4
 // Set to 0 to skip string check
 qualifier = qualifier || 0;
 //如果过滤条件是函数,则通过过滤函数过滤
 if ( jQuery.isFunction( qualifier ) ) {
  return jQuery.grep(elements, function( elem, i ) {
   var retVal = !!qualifier.call( elem, i, elem );
   return retVal === keep;
  });
 //如果过滤条件是DOM相关类型,通过比较节点是否相同来过滤
 } else if ( qualifier.nodeType ) {
  return jQuery.grep(elements, function( elem ) {
   return ( elem === qualifier ) === keep;
  });
 //如果过滤条件是字符串
 } else if ( typeof qualifier === "string" ) {
  //过滤出elements中的节点元素
  var filtered = jQuery.grep(elements, function( elem ) {
   return elem.nodeType === 1;
  });
  // 其中isSimple = /^.[^:#\[\.,]*$/
  if ( isSimple.test( qualifier ) ) {
   return jQuery.filter(qualifier, filtered, !keep);
  } else {
   //查找filtered中满足筛选条件qualifier的节点
   qualifier = jQuery.filter( qualifier, filtered );
  }
 }
 //过滤出elements中满足过滤条件的元素
 return jQuery.grep(elements, function( elem ) {
  return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
 });
}

jQuery.grep is used, click here for detailed explanation of grep.

jQuery.filter(expr, elems, not) This low-level API is specially used to handle the case where the filter condition in jQuery.fn.filter is a string.

jQuery.filter: function( expr, elems, not ) {
 if ( not ) {
  expr = ":not(" + expr + ")";
 }
 //其中matchesSelector和matches是Sizzle中的函数。matchesSelector是判断单个元素elem是否满足表达式expr,matches是查找元素集合elems中满足表达式expr的项
 return elems.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 ( typeof elem === "string" ) {
 //在数组jQuery( elem )中搜索指定的值,并返回其索引值
 return jQuery.inArray( this[0], jQuery( elem ) );
}

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

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

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

【相关教程推荐】

1. JavaScript视频教程
2. JavaScript在线手册
3. bootstrap教程

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn