Semblable à jQuery .closest () mais traversant des descendants?

Existe-t-il une fonction similaire à jQuery .closest() mais pour parcourir les descendants et ne renvoyer que les plus proches?

Je sais qu’il y a la fonction .find() , mais elle retourne toutes les correspondances possibles, pas la plus proche.

Modifier:

Voici la définition du plus proche (au moins pour moi) :

En premier lieu, tous les enfants sont traversés, puis chaque enfant est traversé.

Dans l’exemple donné ci-dessous, id='2' est le plus proche. .closest plus .closest de id="find-my-closest-descendant"

 

S’il vous plaît voir le lien JSfiddle .

Selon votre définition du closest , j’ai écrit le plugin suivant:

 (function($) { $.fn.closest_descendent = function(filter) { var $found = $(), $currentSet = this; // Current place while ($currentSet.length) { $found = $currentSet.filter(filter); if ($found.length) break; // At least one match: break loop // Get all children of the current set $currentSet = $currentSet.children(); } return $found.first(); // Return first match of the collection } })(jQuery); 

Si par descendant “le plus proche” vous voulez dire le premier enfant, alors vous pouvez faire:

 $('#foo').find(':first'); 

Ou:

 $('#foo').children().first(); 

Ou, pour rechercher la première occurrence d’un élément spécifique, vous pouvez faire:

 $('#foo').find('.whatever').first(); 

Ou:

 $('#foo').find('.whatever:first'); 

En réalité, nous avons besoin d’une définition solide de ce que signifie le «descendant le plus proche».

Par exemple

 

Quel serait $('#foo').closestDescendent('span') ?

Vous pouvez utiliser find avec le :first sélecteur:

 $('#parent').find('p:first'); 

La ligne ci-dessus trouvera le premier élément

dans les descendants de #parent .

Qu’en est-il de cette approche?

 $('find-my-closest-descendant').find('> div'); 

Ce sélecteur “enfant direct” fonctionne pour moi.

Je pense que vous devez d’abord définir ce que signifie “le plus proche”. Si vous voulez dire que le nœud descendant correspondant à vos critères est la distance la plus courte en termes de liens parentaux, alors utiliser “: first” ou “.eq (0)” ne fonctionnera pas nécessairement:

 

Dans cet exemple, le deuxième élément “.target” est “plus proche” du “start”

, car il ne s’agit que d’un seul saut parental. Si c’est ce que vous entendez par “plus proche”, vous devez trouver la distance minimale dans une fonction de filtre. La liste de résultats d’un sélecteur jQuery est toujours dans l’ordre DOM.

Peut être:

 $.fn.closestDescendant = function(sel) { var rv = $(); this.each(function() { var base = this, $base = $(base), $found = $base.find(sel); var dist = null, closest = null; $found.each(function() { var $parents = $(this).parents(); for (var i = 0; i < $parents.length; ++i) if ($parents.get(i) === base) break; if (dist === null || i < dist) { dist = i; closest = this; } }); rv.add(closest); }); return rv; }; 

C'est en quelque sorte un plugin de hack en raison de la façon dont il construit l'object de résultat, mais l'idée est que vous devez trouver le chemin parent le plus court parmi tous les éléments correspondants que vous trouvez. Ce code polarise les éléments vers la gauche dans l’arbre DOM à cause du < check; <= serait biaiser à droite.

J’ai préparé ceci, pas d’implémentation pour les sélecteurs de position (ils ont besoin de plus que de simples sélecteurs):

Démo: http://jsfiddle.net/TL4Bq/3/

 (function ($) { var matchesSelector = jQuery.find.matchesSelector; $.fn.closestDescendant = function (selector) { var queue, open, cur, ret = []; this.each(function () { queue = [this]; open = []; while (queue.length) { cur = queue.shift(); if (!cur || cur.nodeType !== 1) { continue; } if (matchesSelector(cur, selector)) { ret.push(cur); return; } open.unshift.apply(open, $(cur).children().toArray()); if (!queue.length) { queue.unshift.apply(queue, open); open = []; } } }); ret = ret.length > 1 ? jQuery.unique(ret) : ret; return this.pushStack(ret, "closestDescendant", selector); }; })(jQuery); 

Il y a probablement quelques bugs, mais je ne l’ai pas beaucoup testé.

La réponse de Rob W n’a pas vraiment fonctionné pour moi. Je l’ai adapté à ce qui a fonctionné.

 //closest_descendent plugin $.fn.closest_descendent = function(filter) { var found = []; //go through every matched element that is a child of the target element $(this).find(filter).each(function(){ //when a match is found, add it to the list found.push($(this)); }); return found[0]; // Return first match in the list } 

J’utiliserais les éléments suivants pour inclure la cible elle-même si elle correspond au sélecteur:

  var jTarget = $("#doo"); var sel = '.pou'; var jDom = jTarget.find(sel).addBack(sel).first(); 

Balisage:

 
poo
foo
pooo

Même si c’est un vieux sujet, je n’ai pas pu résister à la mise en œuvre de mon enfant le plus proche. Fournit le premier descendant trouvé avec moins de déplacement (souffle d’abord). L’un est récursif (favori personnel), l’autre utilise une liste de tâches sans récursivité comme extension jQquery.

J’espère que quelqu’un en profite.

Note: Le récursif obtient un débordement de stack, et j’ai amélioré l’autre, maintenant similaire à la réponse précédente donnée.

 jQuery.fn.extend( { closestChild_err : function( selector ) { // recursive, stack overflow when not found var found = this.children( selector ).first(); if ( found.length == 0 ) { found = this.children().closestChild( selector ).first(); // check all children } return found; }, closestChild : function( selector ) { var todo = this.children(); // start whith children, excluding this while ( todo.length > 0 ) { var found = todo.filter( selector ); if ( found.length > 0 ) { // found closest: happy return found.first(); } else { todo = todo.children(); } } return $(); }, }); 

Le plugin suivant renvoie les descendants les plus proches.

 $.fn.getNthClosestDescendants = function(n, type) { var closestMatches = []; var children = this.children(); recursiveMatch(children); function recursiveMatch(children) { var matches = children.filter(type); if ( matches.length && closestMatches.length < n ) { var neededMatches = n - closestMatches.length; var matchesToAdd = matches.slice(0, neededMatches); matchesToAdd.each(function() { closestMatches.push(this); }); } if (closestMatches.length < n) { var newChildren = children.children(); recursiveMatch(newChildren); } } return closestMatches; }; 

Je cherchais une solution similaire (je voulais tous les descendants les plus proches, c’est-à-dire les premiers + tous les matches, quel que soit le niveau), voici ce que j’ai fait:

 var item = $('#find-my-closest-descendant'); item.find(".matching-descendant").filter(function () { var $this = $(this); return $this.parent().closest("#find-my-closest-descendant").is(item); }).each(function () { // Do what you want here }); 

J’espère que ça aide.

vous avez beaucoup d’options, cependant $("#parent").children(".child"); est le fastet. vérifier cet article pour plus de détails et de référence