Metodo jQuery .live () vs .on () per l'aggiunta di un evento click dopo aver caricato html dinamico


217

Sto usando jQuery v.1.7.1 in cui il metodo .live () è apparentemente deprecato.

Il problema che sto riscontrando è che quando si carica in modo dinamico html in un elemento usando:

$('#parent').load("http://..."); 

Se provo ad aggiungere un evento click in seguito, non registra l'evento usando uno di questi metodi:

$('#parent').click(function() ...); 

o

// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...); 

Qual è il modo corretto per ottenere questa funzionalità? Sembra funzionare solo con .live () per me, ma non dovrei usare quel metodo. Nota che #child è un elemento caricato dinamicamente.

Grazie.


25
Perché dici "presumibilmente deprecato" ? Non credi ai documenti?

6
Non è presumibilmente deprecato: è deprecato. Se guardi il documento jQuery perché.live() ti dice come riscrivere gli usi esistenti .live()da usare .delegate()o .on()(a seconda che tu sia nella versione 1.7+ o meno). Si noti tuttavia che se si aggiunge un gestore con .click()"after" come indicato, vale a dire, dopo aver caricato dinamicamente gli elementi, dovrebbe funzionare - l'unico problema è provare ad assegnare con .click() prima di caricare dinamicamente gli elementi.
nnnnnn,

Ho cambiato la formulazione in "apparentemente" poiché è sostanzialmente quello che volevo dire. Comunque, ora capisco che, ovviamente, poiché l'evento .load () è asincrono, l'elemento #child poteva essere riconosciuto in modo affidabile solo nel gestore del successo, il che ha senso.
Sean Thoman,

Possibile duplicato del binding
showdev

Risposte:


606

Se vuoi che il gestore di clic funzioni per un elemento che viene caricato in modo dinamico, allora imposti il ​​gestore di eventi su un oggetto padre (che non viene caricato in modo dinamico) e gli dai un selettore che corrisponda al tuo oggetto dinamico in questo modo:

$('#parent').on("click", "#child", function() {});

Il gestore eventi verrà collegato #parentall'oggetto e ogni volta che si verifica un evento click su di esso che ha avuto origine #child, genererà il gestore clic. Questo si chiama gestione degli eventi delegati (la gestione degli eventi è delegata a un oggetto padre).

Viene fatto in questo modo perché è possibile associare l'evento #parentall'oggetto anche quando l' #childoggetto non esiste ancora, ma quando in seguito esiste e viene cliccato, l'evento click passerà #parentall'oggetto, vedrà che ha avuto origine #childe c'è un gestore di eventi per fare clic su #childe attivare il tuo evento.


23
Grande spiegazione! Non sono mai stato in grado di avvolgere la testa live()contro, on()ma stasera ho deciso di nuovo di provare, e la tua spiegazione ha rivelato immediatamente quello che mi ero perso da sempre. Grazie!
MikeSchinkel,

6
Un milione di aumenti . Ho iniziato a usare knockout prima di rendermi conto che questo era possibile in jQuery per i bambini creati dinamicamente, grazie mille.
Brock Hensley,

9
Dovresti considerare di scrivere un libro o qualcosa del genere: il tuo testo è stato più utile per me rispetto alla pagina intera nei documenti jQuery su « on () ». Molte grazie!
Colesterolo

@ jfriend00 ti capita di sapere come possiamo applicare questo stesso processo a una situazione hover, non hover? c'è una fonte che ne parla?
Klewis,

@blackhawk - Vedi questa risposta . È possibile registrarsi per le mouseentere mouseleavemanifestazioni e di prova all'interno del gestore cui si è stata innescata. L'evento pseudo "hover" di jQuery non è disponibile con la delega.
jfriend00,

33

Prova questo:

$('#parent').on('click', '#child', function() {
    // Code
});

Dalla $.on()documentazione:

I gestori di eventi sono associati solo agli elementi attualmente selezionati; devono esistere sulla pagina nel momento in cui il codice effettua la chiamata .on().

Il tuo #childelemento non esiste quando lo chiami $.on(), quindi l'evento non è associato (diversamente $.live()). #parentTuttavia, fa esistono, in modo vincolante l'evento che è bene.

Il secondo argomento nel mio codice precedente funge da 'filtro' per innescarsi solo se l'evento traboccava #parentda #child.


Se chiamo il metodo $ .on () dopo il metodo $ .load (), allora perché l'elemento #child non esiste a quel punto?
Sean Thoman,

6
@SeanThoman - dovresti chiamarlo dal gestore del successo del .load()metodo - non dal codice dopo il .load()metodo. #childè noto per essere caricato solo quando il gestore del successo viene effettivamente eseguito e non prima.
jfriend00,

e anche in questo caso il tempo necessario per inserire qualsiasi dato che hai ottenuto nel DOM significa che potrebbe non connettersi. Ultimamente ho lavorato molto su app a pagina singola e il mio standard è var $ body = $ ('body'); $ body.on ("event", ".element / # class", function (e) {}); per tutto. 1 selettore. Nessuna preoccupazione per ciò che è o non è caricato.
lupos,

21

$(document).on('click', '.selector', function() { /* do stuff */ });

EDIT: sto fornendo un po 'più di informazioni su come funziona, perché ... parole. Con questo esempio, stai posizionando un ascoltatore sull'intero documento.

Quando ci si trova clicksu uno o più elementi corrispondenti .selector, l'evento passa al documento principale, a condizione che non vi siano altri listener che chiamano event.stopPropagation()metodo, che porterebbe il gorgoglio di un evento agli elementi padre.

Invece di associarti a uno specifico elemento o insieme di elementi, stai ascoltando qualsiasi evento proveniente da elementi che corrispondono al selettore specificato. Ciò significa che è possibile creare un listener, una volta, che corrisponderà automaticamente agli elementi attualmente esistenti e a tutti gli elementi aggiunti dinamicamente.

Questo è intelligente per alcuni motivi, tra cui prestazioni e utilizzo della memoria (in applicazioni su larga scala)

MODIFICARE:

Ovviamente, l'elemento genitore più vicino su cui puoi ascoltare è migliore e puoi usare qualsiasi elemento al posto di documentfintanto che i bambini per cui vuoi monitorare gli eventi sono all'interno di quell'elemento genitore ... ma che in realtà non ha nulla da fare con la domanda.


23
Ci ha provato $(element).on(...). Questo è $(document).on(...,element,...). Animali diversi.
cHao,

@ArnoldRoa sì, prestazioni migliori. non avrai un listener su più figli, non dovrai riapplicare il listener ogni volta che il DOM viene modificato e gli eventi passano attraverso il DOM per impostazione predefinita. Esegui una volta e ogni bambino corrispondente al selettore attiverà la data funzione quando viene cliccato.
L422Y,

Il commento di @ L422Y qui è molto fuorviante. Se sei curioso delle implicazioni sulle prestazioni, dai un'occhiata al commento di @ jfriend00 sulla risposta di @ Jared
Gust van de Wal,

@GustvandeWal Come è fuorviante? Se vai ed emetti un centinaio di $ (questo) .on (...) rispetto all'ascolto di un evento una volta su un elemento genitore, è sostanzialmente più performante.
L422Y,

Stai solo parlando di allegare gli eventi. I colli di bottiglia nelle prestazioni del mondo reale sono troppi ascoltatori che si attivano (come quelli che deleghi), non grandi quantità di elementi che richiedono un evento associato.
Gust van de Wal,

12

L'equivalente di .live () in 1.7 è simile al seguente:

$(document).on('click', '#child', function() ...); 

Fondamentalmente, guarda il documento per gli eventi click e filtrali per #child.


Perché è così che il gestore di eventi si collega al documento (come .live()fa).
cHao,

17
Uno dei motivi che .live()è deprecato ora è perché è male mettere tutti i gestori di eventi live sull'oggetto documento. Le cose possono davvero, davvero rallentare. Non solo gli eventi devono passare al documento fino al documento, ma è possibile che ci siano molti gestori di eventi da esaminare sull'oggetto documento. Il vantaggio principale di .on()è che puoi collegarlo a un oggetto padre che è molto più vicino all'oggetto reale e migliorare drasticamente le prestazioni. Quindi ... NON consiglierei l'uso .on()con l'oggetto documento. Molto meglio scegliere un oggetto genitore più vicino.
jfriend00,

Grazie per il chiarimento. Per quello che vale, le prestazioni degli eventi sono state notevolmente migliorate con on (), quindi dovrebbe essere un problema minore rispetto al passato. Se si allega a un genitore, suppongo che dovrebbe essere un genitore che esiste sul documento pronto o vedresti problemi simili.
Jared

Nel peggiore dei casi, questo non emulare il deprecato .live()approccio; tuttavia la capacità di controllare la delega è certamente vantaggiosa.
Dan Lugg

9

So che è un po 'tardi per una risposta, ma ho creato un polyfill per il metodo .live (). L'ho provato in jQuery 1.11 e sembra funzionare abbastanza bene. So che dovremmo implementare il metodo .on () laddove possibile, ma nei grandi progetti, dove non è possibile convertire tutte le chiamate .live () in chiamate .on () equivalenti per qualsiasi motivo, il seguente potrebbe lavoro:

if(jQuery && !jQuery.fn.live) {
    jQuery.fn.live = function(evt, func) {
        $('body').on(evt, this.selector, func);
    }
}

Includilo semplicemente dopo aver caricato jQuery e prima di chiamare live ().


5

.on () è per jQuery versione 1.7 e successive. Se hai una versione precedente, usa questo:

$("#SomeId").live("click",function(){
    //do stuff;
});

8
OP dice "Sto usando jQuery v.1.7.1"
Selvakumar Arumugam,

1
@jfriend - perché non pubblicare la tua risposta invece di sottovalutare la mia? Uso live () ogni giorno con tutte le versioni precedenti alla 1.6 e funziona benissimo. Vedo che sei bravo a leggere la documentazione, ma a volte è più utile mettere in pratica qualcosa per una persona. .live () funziona. Periodo.
Matt Cashatt,

5
@MatthewPatrickCashatt - ho pubblicato la mia risposta e non ho votato in negativo la tua - non andare a fare ipotesi così cieche. Pre 1.7, ha .delegate()prestazioni molto migliori rispetto alle .live()quali il motivo per cui il documento jQuery lo consiglia e si depreca .live(). Sì, .live()funziona ancora, ma le risposte qui su SO dovrebbero raccomandare il modo migliore di fare le cose. L'ho visto 20 volte qui su SO. Se .live()pubblichi un codice con qui su SO, verrà ridimensionato (di solito non da me, a meno che non ci sia qualcos'altro di gravemente sbagliato).
jfriend00,

1
Non ho effettuato il downvote, ma anche se .live()sicuramente funziona anche nella versione 1.7, dovresti comunque usarlo .delegate()o .on()perché è .live()stato deprecato per una buona ragione. Fintanto che noti che la modifica della sintassi per le due nuove funzioni funzionerà bene.
nnnnnn,

1
@ jfriend00- Hai assolutamente ragione. Lunga giornata. Mie scuse.
Matt Cashatt,

3

Ho usato "live" nel mio progetto, ma uno dei miei amici mi ha suggerito di usare "on" anziché live. E quando ho provato a usarlo ho riscontrato un problema come te.

Sulle mie pagine creo dinamicamente righe di tabelle di pulsanti e molte cose dom. ma quando uso la magia è scomparsa.

Le altre soluzioni come usarlo come un bambino chiamano le tue funzioni ogni volta ad ogni clic. Ma trovo un modo per farlo accadere di nuovo ed ecco la soluzione.

Scrivi il tuo codice come:

function caller(){
    $('.ObjectYouWntToCall').on("click", function() {...magic...});
}

Chiama il chiamante (); dopo aver creato l'oggetto nella pagina in questo modo.

$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();

In questo modo la tua funzione viene chiamata quando si suppone che non tutti i clic sulla pagina.

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.