2009-12-01 5 views
16

Les méthodes next, prev, nextAll et prevAll sont très utiles, mais pas si les éléments que vous essayez de trouver ne sont pas dans le même élément parent. Ce que je veux faire quelque chose comme ceci:jQuery rechercher les éléments next/prev d'une certaine classe mais pas forcément les frères

<div> 
    <span id="click">Hello</span> 
</div> 
<div> 
    <p class="find">World></p> 
</div> 

Lorsque la durée de l'identifiant click est pressé, je veux correspondre à l'élément suivant avec la classe find, qui dans ce cas ne sont pas frères et soeurs de la cliquée élément donc next() ou nextAll() ne fonctionnera pas.

+0

double possible de [jQuery pour trouver tous les éléments précédents qui correspondent à une expression] (http://stackoverflow.com/questions/322912/jquery-to-find-all-previous-elements-that-match- an-expression) – sachleen

Répondre

8

je travaillais sur ce problème moi-même aujourd'hui, voici ce que je suis venu avec:

/** 
* Find the next element matching a certain selector. Differs from next() in 
* that it searches outside the current element's parent. 
* 
* @param selector The selector to search for 
* @param steps (optional) The number of steps to search, the default is 1 
* @param scope (optional) The scope to search in, the default is document wide 
*/ 
$.fn.findNext = function(selector, steps, scope) 
{ 
    // Steps given? Then parse to int 
    if (steps) 
    { 
     steps = Math.floor(steps); 
    } 
    else if (steps === 0) 
    { 
     // Stupid case :) 
     return this; 
    } 
    else 
    { 
     // Else, try the easy way 
     var next = this.next(selector); 
     if (next.length) 
      return next; 
     // Easy way failed, try the hard way :) 
     steps = 1; 
    } 

    // Set scope to document or user-defined 
    scope = (scope) ? $(scope) : $(document); 

    // Find kids that match selector: used as exclusion filter 
    var kids = this.find(selector); 

    // Find in parent(s) 
    hay = $(this); 
    while(hay[0] != scope[0]) 
    { 
     // Move up one level 
     hay = hay.parent();  
     // Select all kids of parent 
     // - excluding kids of current element (next != inside), 
     // - add current element (will be added in document order) 
     var rs = hay.find(selector).not(kids).add($(this)); 
     // Move the desired number of steps 
     var id = rs.index(this) + steps; 
     // Result found? then return 
     if (id > -1 && id < rs.length) 
      return $(rs[id]); 
    } 
    // Return empty result 
    return $([]); 
} 

Donc, dans votre exemple

<div><span id="click">hello</span></div> 
<div><p class="find">world></p></div> 

vous pouvez maintenant trouver et manipuler l'élément « p » en utilisant

$('#click').findNext('.find').html('testing 123'); 

Je doute qu'il interprétera bien sur de grandes structures, mais ici il est :)

+0

Ne fonctionne pas si l'élément que vous voulez sélectionner est un frère ou une soeur. Et il déclare la variable globale "foin". –

+1

Et qui voudrait-on modifier ceci pour trouver Previous? – Relm

+0

très bien écrit! –

0

Je pense que la seule façon de résoudre ce problème est de faire une recherche récursive sur les éléments après l'élément courant. Il n'y a pas de solution simple à ce problème fourni par jQuery. Si vous voulez seulement trouver des éléments dans les frères et soeurs de votre élément parent (comme c'est le cas dans votre exemple), il n'est pas nécessaire de faire une recherche récursive, mais vous devez faire plusieurs recherches.

J'ai créé un exemple (en fait, ce n'est pas récursif) qui fait ce que vous voulez (j'espère). Il sélectionne tous les éléments après l'élément cliqué en cours et les rend rouge:

<script type="text/javascript" charset="utf-8"> 
    $(function() { 
     $('#click').click(function() { 
      var parent = $(this); 
      alert(parent); 
      do { 
       $(parent).find('.find').css('background-color','red'); 
       parent = $(parent).parent(); 
      } while(parent !== false); 
     }); 
    }); 
</script> 
0

L'expression suivante devrait (sauf erreur de syntaxe!) Trouver tous les frères et sœurs du parent qui contiennent un élément p.find puis trouver ces p.find éléments et changement leur couleur au bleu.

$(this).parent().nextAll(":has(p.find)").find(".find").css('background-color','blue'); 

Bien sûr, si la structure de votre page est telle que p.find se produit un niveau de hiérarchie totalement différente (frères et soeurs d'un grand-parent par exemple), il ne fonctionnera pas.

3

Ma solution impliquerait d'ajuster un peu votre balisage pour rendre le jQuery beaucoup plus facile. Si ce n'est pas possible ou pas une réponse attrayante, s'il vous plaît ignorer!

J'enveloppez une enveloppe « parent » autour de ce que vous voulez faire ...

<div class="find-wrapper"> 
    <div><span id="click">hello</span></div> 
    <div><p class="find">world></p></div> 
</div> 

Maintenant, pour trouver le find:

$(function() { 
    $('#click').click(function() { 
     var $target = $(this).closest('.find-wrapper').find('.find'); 
     // do something with $target... 
    }); 
}); 

Cela vous donne la possibilité d'avoir tout type de balisage et de hiérarchie que vous souhaitez dans le wrapper que j'ai suggéré, et toujours trouver votre cible de manière fiable.

Bonne chance!

13

Essayez ceci. Il marquera votre élément, créera un ensemble d'éléments correspondant à votre sélecteur et rassemblera tous les éléments de l'ensemble qui suit votre élément.

$.fn.findNext = function (selector) { 
    var set = $([]), found = false; 
    $(this).attr("findNext" , "true"); 
    $(selector).each(function(i , element) { 
     element = $(element); 
     if (found == true) set = set.add(element) 
     if (element.attr("findNext") == "true") found = true; 
    }) 
    $(this).removeAttr("findNext") 
    return set 
} 

EDIT

solution beaucoup plus simple en utilisant la méthode d'index. l'élément que vous appelez la méthode des besoins d'être sélectionnable par le même sélecteur si

$.fn.findNext = function(selector){ 
    var set = $(selector); 
    return set.eq(set.index(this,) + 1) 
} 

pour libérer la fonction de ce handicap, nous pourrions youse les navigateurs possèdent compareDocumentposition

$.fn.findNext = function (selector) { 
    // if the stack is empty, return the first found element 
    if (this.length < 1) return $(s).first(); 
    var found, 
     that = this.get(0); 
    $(selector) 
    .each(function() { 
     var pos = that.compareDocumentPosition(this); 
     if (pos === 4 || pos === 12 || pos === 20){ 
     // pos === 2 || 10 || 18 for previous elements 
     found = element; 
     return false; 
     }  
    }) 
    // using pushStack, one can now go back to the previous elements like this 
    // $("#someid").findNext("div").remove().end().attr("id") 
    // will now return "someid" 
    return this.pushStack([ found ]); 
}, 

EDIT 2 c'est beaucoup plus facile d'utiliser $ .grep de jQuery. voici le nouveau code

$.fn.findNextAll = function(selector){ 
     var that = this[ 0 ], 
      selection = $(selector).get(); 
     return this.pushStack(
     // if there are no elements in the original selection return everything 
     !that && selection || 
     $.grep(selection, function(n){ 
      return [4,12,20].indexOf(that.compareDocumentPosition(n)) > -1 
     // if you are looking for previous elements it should be [2,10,18] 
     }) 
    ); 
    } 
    $.fn.findNext = function(selector){ 
     return this.pushStack(this.findNextAll(selector).first()); 
    } 

lors de la compression des noms de variables, cela devient un simple doublure.

Éditer 3 en utilisant les opérations au niveau du bit, cette fonction peut être encore plus rapide?

$.fn.findNextAll = function(selector){ 
    var that = this[ 0 ], 
    selection = $(selector).get(); 
    return this.pushStack(
    !that && selection || $.grep(selection, function(n){ 
     return that.compareDocumentPosition(n) & (1<<2); 
     // if you are looking for previous elements it should be & (1<<1); 
    }) 
); 
} 
$.fn.findNext = function(selector){ 
    return this.pushStack(this.findNextAll(selector).first()); 
} 
+0

un inconvénient que je n'ai pas pensé, c'est que l'élément que vous appelez findNext, doit être sélectionnable par le même sélecteur, sinon il va simplement parcourir tout sans trouver votre élément marqué. – lordvlad

+0

Merci, j'ai regardé partout et personne d'autre n'a répondu à l'affaire non-frère aussi succinctement que vous. –

+0

Merci pour votre travail. Avec de très gros documents tabulaires, Edit 2 a accéléré ce que j'essayais de faire par ordre de grandeur! – David

Questions connexes