2009-12-01 15 views
16

I metodi next, prev, nextAll e prevall sono molto utili, ma non se gli elementi che stai cercando di trovare non si trovano nello stesso elemento genitore. Quello che voglio fare è qualcosa di simile:jQuery trova gli elementi next/prev di una certa classe ma non necessariamente i fratelli

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

Quando si preme l'arco con l'id click, voglio corrispondere all'elemento successivo con la classe find, che in questo caso non è un fratello del fatto clic elemento in tal modo next() o nextAll() non funzionerà.

+0

possibile duplicato di [jQuery per trovare tutti gli elementi precedenti che corrispondono a un'espressione] (http://stackoverflow.com/questions/322912/jquery-to-find-all-previous-elements-that-match- an-expression) – sachleen

risposta

8

stavo lavorando su questo problema io stesso oggi, qui è quello che mi si avvicinò con:

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

Quindi nel tuo esempio

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

si potrebbe ora trovare e manipolare l'elemento 'p' utilizzando

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

dubito esso deve svolgere bene su grandi strutture, ma qui è :)

+0

Non funziona se l'elemento che si desidera selezionare è un fratello. E dichiara la variabile globale "fieno". –

+1

E chi potrebbe modificarlo per trovare Previous? – Relm

+0

molto ben scritto! –

0

Penso che l'unico modo per risolvere questo problema sia eseguire una ricerca ricorsiva sugli elementi dopo l'elemento corrente. Non esiste una soluzione semplice a questo problema fornito da jQuery. Se si desidera trovare solo elementi nei fratelli dell'elemento principale (come nel caso dell'esempio), non è necessario eseguire una ricerca ricorsiva, ma è necessario effettuare più ricerche.

Ho creato un esempio (in realtà, non è ricorsivo) che fa quello che vuoi (spero). Si seleziona tutti gli elementi dopo l'elemento cliccato corrente e li rende rosso:

<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

La seguente espressione dovrebbe (salvo errori di sintassi!) Trova tutti i fratelli della controllante che contengono un elemento p.find e poi trovare quei p.find elementi e il cambiamento il loro colore al blu.

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

Naturalmente, se la struttura della pagina è tale che p.find si verifica in un livello completamente diverso di gerarchia (fratello di un nonno, per esempio), non funzionerà.

3

La mia soluzione comporterebbe un aggiustamento del markup un po 'per rendere il jQuery molto più semplice. Se questo non è possibile o non è una risposta attraente, per favore ignora!

Vorrei avvolgere un wrapper 'genitore' attorno a ciò che si vuole fare ...

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

Ora, per trovare la find:

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

Questo ti dà la flessibilità necessaria per avere tutto quello tipo di markup e gerarchia che desideri all'interno del wrapper che ho suggerito e che comunque trovi il tuo obiettivo in modo affidabile.

Buona fortuna!

13

Prova questo. Marcerà il tuo elemento, creerà un insieme di elementi corrispondenti al tuo selettore e raccoglierà tutti gli elementi dal set seguendo il tuo elemento.

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

molto più semplice soluzione con jquerys metodo index. l'elemento si chiama il metodo da deve essere scelta dello stesso selettore se

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

per liberare la funzione da questo handicap, potremmo youse i browser possiedono 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 questo è molto più semplice usando $ .grep di jQuery. ecco il nuovo codice

$.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()); 
    } 

quando comprimendo nomi di variabili Questo diventa un mero due liner.

Edit 3 utilizzando operazioni bit per bit, questa funzione potrebbe essere ancora più veloce?

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

uno svantaggio a cui non ho pensato è che l'elemento che chiamate findNext da, deve essere selezionato dallo stesso selettore, altrimenti semplicemente passerà in rassegna tutto senza trovare l'elemento contrassegnato. – lordvlad

+0

Grazie, ho guardato dappertutto e nessun altro ha risposto al caso non-fratello come succintamente come te. –

+0

Grazie per il tuo lavoro. Con documenti tabulari molto grandi, Modifica 2 ha accelerato ciò che stavo cercando di fare per ordine di grandezza! – David

Problemi correlati