2010-11-26 5 views
0

Comment puis-je obtenir l'élément suivant le plus proche qui sattisfies certaines conditions/fonctions? Comme:jQuery: nextEl = someEl.next (function() {... renvoie vrai/faux;})?

nextEl = someEl.next(function() {... return true to return this from next() });

Je ne suis pas au courant que la méthode .next() dans l'API jQuery prend en charge une fonction comme argument. Y at-il un truc pour l'écrire comme ça sans faire de boucle?

Aussi, je ne veux pas d'abord sélectionner tous les éléments, puis utiliser filter() - ce sous-optimal du point de vue des performances.

+0

Etes-vous absolument certain que cette condition ne peut pas être satisfaite par un autre sélecteur? – zincorp

+0

Oui. Aussi, je ne veux pas sélectionner tous les éléments d'abord, puis utiliser filter() - ce sous-optimal du point de vue de la performance. – tillda

+0

J'ai mis à jour ma réponse pour transformer la version du code natif en un plugin appelé 'nextMatch()', donc la condition ne s'exécute pas plus que nécessaire, et vous ne récupérez pas tous les frères et sœurs suivants avec 'nextAll() '. – user113716

Répondre

2

Obtenez tous les éléments suivants using .nextAll(), puis use .filter() et renvoyez le résultat de la condition. Lorsque la condition renvoie true, l'élément est conservé.

Ensuite affinez-le à the .first() match.

nextEl = someEl.nextAll().filter(function() { 
    return (someCondition); 
}).first(); 

Ou s'il y aura beaucoup d'éléments testés, et vous ne voulez pas courir la condition tous ces temps supplémentaires, utilisez .each(), puis return false; quand la condition est remplie. Cela arrête la boucle.

var nextEl; 

someEl.nextAll().each(function() { 
    if(someCondition) { 
     nextEl = this; // reference the matched element 
     return false; // break the loop 
    } 
}); 

EDIT: Si vous ne souhaitez pas sélectionner tous les prochains éléments, je s'habituer, et d'utiliser une boucle while, quelque chose comme ceci:

var nextEl = someEl[0]; 

while(nextEl = nextEl.nextSibling) { 
    if(someCondition) { 
     break; 
    } 
} 

La boucle se rompra dès que la condition sera remplie et l'affectation la plus récente à nextEl sera votre élément.

Si la condition est jamais remplie, la boucle se terminera quand il court d'éléments, et nextEl sera null ou undefined (je ne me souviens plus).

Cela devrait être un moyen très rapide de le faire.


EDIT:

est ici une version de fonction de celui-ci. Il accepte l'élément de départ et une fonction qui exécute le test. Ensuite, il renvoie le résultat trouvé, ou undefined.

function nextMatch(el, func) { 
    while(el = el.nextSibling) { 
     if(func()) { 
      return el; 
     } 
    } 
} 

    // nextEl will contain the match, or "undefined" 
var nextEl = nextMatch(someEl, function() { 
    return (someTest); 
}); 

var someOtherEl = nextMatch(someEl, function() { 
    return (someOtherTest); 
}); 

LAST EDIT:

Je suppose que je pourrais aussi bien faire un plugin:

(function($) { 
    $.fn.nextMatch = function(func) { 
     return this.map(function() { 
      var el = this; 
      while(el = el.nextSibling) { 
       if(el.nodeType === 1 && func.call(el)) { 
        return el; 
       } 
      } 
     }); 
    } 
})(jQuery); 

var nextEl = someEl.nextMatch(function() { 
    return (someTest); 
}); 

Alors maintenant, il est plus d'une solution de type jQuery. Vous devriez toujours avoir de meilleures performances car il ne récupère pas tous les frères et sœurs suivants, et la boucle while se brise quand une correspondance est trouvée.

+0

Cela fonctionne, mais il y a une certaine pénalité de performance pour sélectionner tous les éléments Donc je ne voulais pas l'utiliser. – tillda

+0

@tillda - Est la pénalité dans le test de condition, ou juste dans la sélection des éléments. J'ai ajouté une réponse qui arrête les conditions après la première fois qu'il est satisfait. Si vous ne voulez pas le '.nextAll()', vous pouvez utiliser une boucle 'while'. Je vais donner une mise à jour. – user113716

+0

En fait, 'return false;' dans le 'filter' ne casse pas la boucle. Il supprime simplement cet élément des résultats de 'filter'. Donc, en fait, cela sélectionne le dernier jumelage correspondant (regardez [ici] (http://jsfiddle.net/cambraca/vQPC4/1/)) – cambraca

1

Essayez ceci:

nextEl = someEl.nextAll('.a').first().css('color', 'red'); 

La condition est dans ce cas il a la classe a, et il tourne la couleur rouge (comme un simple indicateur).

Regardez-le fonctionner here.

+0

Désolé, ce n'est pas ce que je veux. Je veux spécifier si par une ** fonction **. De plus, je ne veux pas faire correspondre tous les éléments en premier à cause de la performance. – tillda

+0

vous pouvez utiliser 'next()' pour faire cela: 'nextEl = someEl.next ('. A');' –

+1

@ Frédéric Hamidi: en fait, vous ne pouvez pas. Si l'élément suivant ne correspond pas, il ne regarde pas plus loin, il ne renvoie rien. – cambraca

Questions connexes