Alla ricerca del metodo find (..) di jQuery che include il nodo corrente


134

Il metodo traversal di jQuery find (..) non include il nodo corrente, ma inizia con i figli del nodo corrente. Qual è il modo migliore per chiamare un'operazione di ricerca che include il nodo corrente nel suo algoritmo di corrispondenza? Guardando attraverso i documenti nulla mi salta immediatamente fuori.

Risposte:


153

Per jQuery 1.8 e versioni successive, è possibile utilizzare .addBack(). Richiede un selettore, quindi non è necessario filtrare il risultato:

object.find('selector').addBack('selector')

Prima di jQuery 1.8 eri bloccato .andSelf(), (ora deprecato e rimosso) che quindi aveva bisogno di filtraggio:

object.find('selector').andSelf().filter('selector')

5
L'ho raggruppato come un plugin jquery.findIncludeSelf, registrato con Bower. Vedi github.com/ronen/jquery.findIncludeSelf
ronen

18
@ronen Un file extra per qualcosa che può essere fatto in una riga? No grazie.

6
@ prc322 un file aggiuntivo non mi dà fastidio per le distribuzioni che raggruppano comunque tutto il javascript in un singolo file. In genere preferisco usare metodi di libreria (testati) anche per cose semplici, piuttosto che ingombrare il mio codice con cose che trovo più difficili da leggere e che introducono più possibilità per i bug. In questo caso in particolare, IMHO la necessità di specificare 'selector'due volte rende l'incapsulamento extra desiderabile. YMMV
Ron

Ok, quindi potrei essere spessa, ma non è necessario specificare 'selector'due volte (come menzionato da @ronen), non potresti semplicemente usare object.parent().find('selector')??? - detto questo mi piace l'idea di una lib che lo fa per te.
Sam,

8
@ circa1983 object.parent().find('selector')include i fratelli objecte i loro discendenti.
Robert,

41

Non puoi farlo direttamente, il più vicino a cui riesco a pensare è usare .andSelf()e chiamare .filter(), in questo modo:

$(selector).find(oSelector).andSelf().filter(oSelector)
//or...
$(selector).find('*').andSelf().filter(oSelector);

Sfortunatamente .andSelf()non accetta un selettore, il che sarebbe utile.


7
Hai persino aggiunto un commento alla pagina jquery subito dopo aver risposto a questa domanda api.jquery.com/andSelf/#comment-50124533 Questa è completezza. Bello! Ho fatto la mia dovuta diligenza e ho apprezzato anche quello.
John K,

2
Il secondo sarebbe incredibilmente lento. Il primo è semplicemente lento.
Tgr,

@Tgr - Non sono in disaccordo, anche se il primo non dovrebbe essere quello show se non hai a che fare con un numero molto elevato di elementi. Se non hai bisogno di concatenare, puoi sicuramente saltare il ri-filtraggio di quegli elementi.
Nick Craver

3
È interessante notare che closest(..)include l'elemento DOM corrente e su l'albero mentre tutti i metodi di attraversamento dell'albero come find(..)etc non corrispondono all'elemento corrente. È come se il team jQuery li avesse implementati intenzionalmente senza sovrapposizioni quando entrambe le operazioni venivano usate insieme per una ricerca verticale completa.
John K,

17
Tieni presente che .andSelf () è stato deprecato dalla v1.8 e sostituito con .addBack () che accetta un selettore come argomento. Vedi api.jquery.com/addBack
kkara l'

9

Definire

$.fn.findSelf = function(selector) {
    var result = this.find(selector);
    this.each(function() {
        if ($(this).is(selector)) {
            result.add($(this));
        }
    });
    return result;
};

quindi utilizzare

$.findSelf(selector);

invece di

$find(selector);

Purtroppo jQuery non ha questo built-in. Davvero strano per così tanti anni di sviluppo. I miei gestori AJAX non sono stati applicati ad alcuni elementi principali a causa del funzionamento di .find ().


Questo è un bug. Si aggiunge tutti "sé", anche se solo uno di essi corrisponde ... - Una delle ragioni di questo bug è un metodo di jQuery crappily chiamato ...
Robert Siemer

Ho provato a correggere il bug che hai segnalato. Funziona correttamente adesso?
Dmitriy Sintsov il

La maggior parte delle altre risposte usa filter()lì, il che ha più senso.
Robert Siemer,

5
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))

È possibile memorizzare $('selector')in una variabile per l'accelerazione. Puoi anche scrivere una funzione personalizzata per questo se ne hai bisogno molto:

$.fn.andFind = function(expr) {
  return this.find(expr).add(this.filter(expr));
};

$('selector').andFind('otherSelector')

Questo funziona solo se stai iniziando con un selettore, ma potrebbe non essere il caso. Inoltre, è errato, sarebbe $('selector').find('otherSelector').add($('otherSelector')), ciò che hai ora è equivalente .andSelf(). Infine, il .andFind()filtro non si basa sull'espressione, è necessario .add($(this).filter(expr)):)
Nick Craver

@Nick Craver: sì, ho dimenticato la parte di filtro, risolta ora. Non importa se $('selector')viene sostituito da un altro metodo per ottenere un oggetto jQuery (se questo è ciò che intendevi non iniziando con un selettore), add()può gestire qualsiasi cosa proprio come $()può.
Tgr,

Il mio punto era che $('selector')potresti essere $('selector').children('filter').closest('.class').last()... potrebbe essere in una catena e non hai idea di quale oggetto stai aggiungendo, quindi la soluzione generica dovrebbe prendere l'oggetto precedente come fa il filtro :)
Nick Craver

Ancora non vedo perché questo sarebbe un problema. thisè qualunque oggetto jQuery sia stato chiamato un plugin. Potrebbe anche essere il risultato di una catena di chiamate.
Tgr,

5

La risposta accettata è molto inefficiente e filtra l'insieme di elementi che sono già abbinati.

//find descendants that match the selector
var $selection = $context.find(selector);
//filter the parent/context based on the selector and add it
$selection = $selection.add($context.filter(selector);

3

Se vuoi che il concatenamento funzioni correttamente, usa lo snippet di seguito.

$.fn.findBack = function(expr) {
    var r = this.find(expr);
    if (this.is(expr)) r = r.add(this);
    return this.pushStack(r);
};

Dopo la chiamata della funzione end restituisce l'elemento #foo.

$('#foo')
    .findBack('.red')
        .css('color', 'red')
    .end()
    .removeAttr('id');

Senza definire plugin extra, sei bloccato con questo.

$('#foo')
    .find('.red')
        .addBack('.red')
            .css('color', 'red')
        .end()
    .end()
    .removeAttr('id');

Ah, no ... Se thisè più di un elemento this.is()è già soddisfatto se solo uno di essi corrisponde.
Robert Siemer,

3

Se stai cercando esattamente un elemento , sia l'elemento corrente o uno al suo interno, puoi usare:

result = elem.is(selector) ? elem : elem.find(selector);

Se stai cercando più elementi puoi usare:

result = elem.filter(selector).add(elem.find(selector));

L'uso di andSelf/ andBackè piuttosto raro, non so perché. Forse a causa dei problemi di performance che alcuni ragazzi hanno menzionato prima di me.

(Ho notato che Tgr ha già dato quella seconda soluzione)


2

So che questa è una vecchia domanda, ma c'è un modo più corretto. Se l'ordine è importante, ad esempio quando si abbina un selettore come :first, ho scritto una piccola funzione che restituirà lo stesso esatto risultato come se find()effettivamente includesse il set corrente di elementi:

$.fn.findAll = function(selector) {
  var $result = $();

  for(var i = 0; i < this.length; i++) {
    $result = $result.add(this.eq(i).filter(selector));
    $result = $result.add(this.eq(i).find(selector));
  }

  return $result.filter(selector);
};

Non sarà efficace in alcun modo, ma è il migliore che ho ideato per mantenere un ordine corretto.


1

Penso che andSelfsia quello che vuoi:

obj.find(selector).andSelf()

Si noti che ciò aggiungerà sempre il nodo corrente, indipendentemente dal fatto che corrisponda o meno al selettore.


1

Se stai osservando rigorosamente i nodi attuali, lo fai semplicemente

$(html).filter('selector')

0

Stavo cercando di trovare una soluzione che non si ripetesse (cioè non inserendo lo stesso selettore due volte).

E questa piccola estensione jQuery lo fa:

jQuery.fn.findWithSelf = function(...args) {
  return this.pushStack(this.find(...args).add(this.filter(...args)));
};

Combina find()(solo discendenti) con filter()(solo l'insieme attuale) e supporta qualsiasi argomento sia mangiato da entrambi. Ciò pushStack()consente .end()di funzionare come previsto.

Usa così:

$(element).findWithSelf('.target')

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.