2009-12-01 14 views
16

Die Methoden next, prev, nextAll und prevAll sind sehr nützlich, aber nicht, wenn sich die Elemente, die Sie suchen, nicht im selben übergeordneten Element befinden. Was ich will, ist, etwas zu tun wie folgt aus:jQuery finde next/prev Elemente einer bestimmten Klasse, aber nicht unbedingt Geschwister

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

Wenn die Spanne mit der ID click gedrückt wird, ich das nächste Element mit der Klasse find, die in diesem Fall übereinstimmen soll kein Bruder des klickten ist Element so next() oder nextAll() wird nicht funktionieren.

+0

möglich Duplikat [jQuery alle bisherigen Elemente zu finden, die einen Ausdruck übereinstimmen] (http://stackoverflow.com/questions/322912/jquery-to-find-all-previous-elements-that-match- an-expression) – sachleen

Antwort

8

ich auf dieses Problem mich heute arbeiten, ist hier, was ich kam mit:

/** 
* 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 $([]); 
} 

So

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

Sie nun das Element 'p' finden konnte und manipulieren, indem

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

ich bezweifle es auf große Strukturen gut funktionieren wird, aber hier ist es :)

+0

Funktioniert nicht, wenn das Element, das Sie auswählen möchten, ein Geschwister ist. Und es deklariert die globale Variable "Heu". –

+1

Und wer würde das ändern, um Previous zu finden? – Relm

+0

sehr gut geschrieben! –

0

Ich denke, der einzige Weg, um dieses Problem zu lösen, ist eine rekursive Suche über die Elemente nach dem aktuellen Element. Es gibt keine einfache Lösung für dieses Problem, das von jQuery bereitgestellt wird. Wenn Sie nur Elemente in den Geschwistern Ihres übergeordneten Elements finden möchten (wie in Ihrem Beispiel), ist keine rekursive Suche erforderlich, Sie müssen jedoch mehrere Suchen durchführen.

Ich habe ein Beispiel erstellt (eigentlich ist es nicht rekursiv), das tut, was Sie wollen (ich hoffe). Er wählt alle Elemente nach dem aktuellen geklickt Element und macht sie rot:

<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

Der folgende Ausdruck sollte (abgesehen von Syntaxfehler!) Alle Geschwister der Eltern finden, die ein p.find Element enthalten und dann finden diese p.find Elemente und ändern ihre Farbe ist blau.

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

Natürlich, wenn Ihre Seitenstruktur so ist, dass p.find in einer völlig anderen Ebene der Hierarchie auftritt (Geschwister eines Großeltern zum Beispiel), wird es nicht funktionieren.

3

Meine Lösung würde bedeuten, Ihr Markup ein wenig anzupassen, um die jQuery viel einfacher zu machen. Wenn dies nicht möglich ist oder keine ansprechende Antwort, bitte ignorieren!

Ich würde wickeln Sie ein ‚Eltern‘ Wrapper um, was Sie tun wollen ...

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

Nun finden die find:

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

Dies gibt Ihnen die Flexibilität zu haben, was auch immer Art von Markup und Hierarchie, die Sie in den von mir vorgeschlagenen Wrapper möchten, und immer noch zuverlässig Ihr Ziel finden.

Viel Glück!

13

Versuchen Sie dies. Es markiert Ihr Element, erstellt eine Reihe von Elementen, die mit Ihrem Selektor übereinstimmen, und sammelt alle Elemente aus dem Satz, der Ihrem Element folgt.

$.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

viel einfachere Lösung jquerys Index-Methode. das Element Sie die Methode von Bedürfnissen rufen durch den gleichen Wähler wählbar sein, obwohl

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

die Funktion von dieser Behinderung zu befreien, wir die Browser 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 besitzen youse könnte Das ist viel einfacher mit jQuery $ .grep. Hier ist der neue 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()); 
    } 

Bei der Komprimierung von Variablennamen wird dies zu einem bloßen Liner.

Bearbeiten 3 Mit bitweisen Operationen kann diese Funktion noch schneller sein?

$.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

Ein Nachteil, an den ich nicht gedacht habe, ist, dass das Element, das Sie findNext from nennen, durch den gleichen Selektor auswählbar sein muss, sonst wird es einfach durch alles durchlaufen, ohne Ihr markiertes Element zu finden. – lordvlad

+0

Danke, ich habe überall nachgeschaut und niemand hat den Nicht-Geschwister-Fall so prägnant beantwortet wie Sie. –

+0

Vielen Dank für Ihre Arbeit. Mit sehr großen tabellarischen Dokumenten hat Edit 2 das, was ich versuchte, um Größenordnungen beschleunigt! – David