jQuery .live () vs .on () metoda dodawania zdarzenia click po załadowaniu dynamicznego HTML


217

Korzystam z jQuery v.1.7.1, gdzie metoda .live () jest najwyraźniej przestarzała.

Problemem jest to, że podczas dynamicznego ładowania HTML do elementu przy użyciu:

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

Jeśli spróbuję później dodać zdarzenie kliknięcia, nie rejestruje ono zdarzenia przy użyciu jednej z następujących metod:

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

lub

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

Jaki jest właściwy sposób na osiągnięcie tej funkcjonalności? Wydaje się, że działa tylko z .live () dla mnie, ale nie powinienem używać tej metody. Zauważ, że #child jest dynamicznie ładowanym elementem.

Dzięki.


25
Dlaczego mówisz „rzekomo przestarzały” ? Nie wierzysz w dokumenty?

6
To nie jest rzekomo przestarzałe: jest przestarzałe. Jeśli spojrzysz na dokumentację jQuery, podpowie.live() ci, jak przepisać istniejące zastosowania .live()użycia .delegate()lub .on()(w zależności od tego, czy korzystasz z wersji 1.7+, czy nie). Pamiętaj jednak, że jeśli dodasz moduł obsługi z .click()„później”, jak wspomniałeś, tj. Po dynamicznym ładowaniu elementów, powinien on działać - jedynym problemem jest próba przypisania go .click() przed dynamicznym ładowaniem elementów.
nnnnnn

Zmieniłem sformułowanie na „pozornie”, ponieważ w zasadzie o to mi chodziło. W każdym razie rozumiem teraz, że ponieważ zdarzenie .load () jest asynchroniczne, wówczas element #child można tylko niezawodnie rozpoznać w module obsługi sukcesu, co ma sens.
Sean Thoman

Odpowiedzi:


606

Jeśli chcesz, aby moduł obsługi kliknięć działał dla elementu ładowanego dynamicznie, ustaw moduł obsługi zdarzeń na obiekcie nadrzędnym (który nie jest ładowany dynamicznie) i nadaj mu selektor pasujący do obiektu dynamicznego w następujący sposób:

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

Program obsługi zdarzeń zostanie dołączony do #parentobiektu i za każdym razem, gdy zdarzenie kliknięcia pojawi się nad nim #child, co spowoduje jego uruchomienie. Nazywa się to obsługą zdarzeń delegowanych (obsługa zdarzeń jest delegowana do obiektu nadrzędnego).

Odbywa się to w ten sposób, ponieważ można dołączyć zdarzenie do #parentobiektu nawet wtedy, gdy #childobiekt jeszcze nie istnieje, ale gdy później będzie istniał i zostanie kliknięty, zdarzenie click spowoduje bąbelkowanie do #parentobiektu, zobaczy, że ono powstało #childi istnieje moduł obsługi zdarzeń do kliknięcia #childi uruchomienia zdarzenia.


23
Świetne wyjaśnienie! Nigdy wcześniej nie było w stanie owinąć głowę wokół live()vs. on()ale dzisiaj postanowiłem jeszcze raz spróbować, a wyjaśnienie natychmiast ujawnił, czego brakowało przez cały czas. Dzięki!
MikeSchinkel

6
Milion wzlotów . Zacząłem używać nokautu, zanim zdałem sobie sprawę, że jest to możliwe w jQuery dla dynamicznie tworzonych dzieci, dziękuję bardzo.
Brock Hensley,

9
Powinieneś rozważyć napisanie książki lub czegoś takiego: twój mały tekst był dla mnie bardziej pomocny niż pełna strona w dokumentach jQuery o « on () ». Wielkie dzięki!
Cholesterol,

@ jfriend00, czy wiesz, jak możemy zastosować ten sam proces w przypadku zawisu, a nie zawisu? czy jest jakieś źródło, które o tym mówi?
klewis

@blackhawk - Zobacz tę odpowiedź . Możesz się zarejestrować za mouseenteri mouseleavewydarzeń oraz badania wewnątrz przewodnika, który z nich został wyzwolony. Pseudo „hover” zdarzenia jQuery nie jest dostępne w przypadku delegowania.
jfriend00

33

Spróbuj tego:

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

Z $.on()dokumentacji:

Procedury obsługi zdarzeń są powiązane tylko z aktualnie wybranymi elementami; muszą istnieć na stronie w momencie, gdy Twój kod wywołuje połączenie .on().

Twój #childelement nie istnieje, gdy go wywołujesz $.on(), więc wydarzenie nie jest powiązane (w przeciwieństwie do $.live()). #parentJednak nie istnieje, więc związanie zdarzenie, które jest w porządku.

Drugi argument w moim kodu powyżej działa jak filtr „” to tylko spust, jeśli zdarzenie przepuszczano do #parentz #child.


Jeśli wywołam metodę $ .on () po metodzie $ .load (), to dlaczego element #child nie istniałby w tym momencie?
Sean Thoman

6
@SeanThoman - należy wywołać go z modułu obsługi sukcesu .load()metody - nie z kodu po .load()metodzie. #childwiadomo, że jest ładowany tylko wtedy, gdy moduł obsługi sukcesu faktycznie się wykonuje, a nie wcześniej.
jfriend00

i nawet wtedy czas potrzebny na wstawienie danych, które odzyskałeś do DOM, oznacza, że ​​może się nie połączyć. Ostatnio dużo pracuję nad aplikacjami na jednej stronie, a moim standardem jest var $ body = $ ('body'); $ body.on („event”, „.element / # class”, function (e) {}); za wszystko. 1 selektor. Nie martw się o to, co jest załadowane lub nie.
lupos

21

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

EDYCJA: Podaję trochę więcej informacji o tym, jak to działa, ponieważ ... słowa. W tym przykładzie umieszczasz detektor na całym dokumencie.

Podczas clickdopasowywania dowolnego elementu (-ów) .selectorzdarzenie przechodzi do głównego dokumentu - o ile nie ma innych detektorów wywołujących event.stopPropagation()metodę - które nadpisałyby bąbelkowanie zdarzenia do elementów nadrzędnych.

Zamiast wiązania z określonym elementem lub zestawem elementów, nasłuchujesz wszelkich zdarzeń pochodzących z elementów pasujących do określonego selektora. Oznacza to, że możesz jednorazowo utworzyć jednego detektora, który automatycznie dopasuje aktualnie istniejące elementy, a także dowolne elementy dodawane dynamicznie.

Jest to sprytne z kilku powodów, w tym wydajności i wykorzystania pamięci (w aplikacjach na dużą skalę)

EDYTOWAĆ:

Oczywiście najbliższy element nadrzędny, którego możesz słuchać, jest lepszy i możesz użyć dowolnego elementu, o documentile dzieci, dla których chcesz monitorować zdarzenia, znajdują się w tym elemencie nadrzędnym ... ale to naprawdę nie ma nic do roboty z pytaniem.


23
Próbował $(element).on(...). Jest $(document).on(...,element,...). Różne bestie.
cHao

@ArnoldRoa tak, lepsza wydajność. nie będziesz mieć detektora na wielu elementach podrzędnych, nie będziesz musiał ponownie stosować detektora za każdym razem, gdy DOM zostanie zmodyfikowany, a zdarzenia będą domyślnie przechodzić przez DOM. Uruchom raz, a każde dziecko pasujące do selektora uruchomi daną funkcję po kliknięciu.
L422Y,

Komentarz L422Y tutaj jest bardzo mylący. Jeśli jesteś ciekawy wpływ na wydajność, przyjrzeć użytkownika @ jfriend00 komentarzu na @ odpowiedź Jareda
Gust van de Wal

@GustvandeWal Jak to jest mylące? Jeśli pójdziesz i wydasz sto $ (this) .on (...) vs nasłuchiwanie zdarzenia raz na elemencie nadrzędnym, jest to znacznie bardziej wydajne.
L422Y,

Mówisz tylko o dołączaniu wydarzeń. W rzeczywistych wąskich gardłach wydajności występuje zbyt duża liczba słuchaczy odpalających (takich jak te, które delegujesz), a nie duże ilości elementów, które wymagają dołączonego zdarzenia.
Gust van de Wal

12

Odpowiednik .live () w wersji 1.7 wygląda następująco:

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

Zasadniczo obejrzyj dokument pod kątem zdarzeń kliknięcia i przefiltruj je pod kątem #child.


Ponieważ w ten sposób moduł obsługi zdarzeń dołącza się do dokumentu (tak się .live()dzieje).
cHao

17
Jednym z powodów, który .live()jest już nieaktualny, jest to, że źle jest umieścić wszystkie procedury obsługi zdarzeń na żywo w obiekcie dokumentu. Rzeczy mogą naprawdę, naprawdę zwolnić. Zdarzenia muszą być nie tylko bąbelkowane aż do dokumentu, ale możesz mieć wiele programów obsługi zdarzeń do przeglądania obiektu dokumentu. Główną zaletą .on()jest to, że można dołączyć go do obiektu nadrzędnego, który jest znacznie bliżej rzeczywistego obiektu i drastycznie poprawić wydajność. Więc ... NIE zalecałbym używania .on()z obiektem dokumentu. Znacznie lepiej wybrać bliższy obiekt nadrzędny.
jfriend00

Dziękuję za wyjaśnienie. Pod względem wartości wydajność wydarzeń została znacznie ulepszona dzięki funkcji on (), więc powinno to być mniejszy problem niż kiedyś. Przyłączając się do rodzica, zakładam, że musiałby to być rodzic, który istnieje w dokumencie gotowy, inaczej wystąpiłyby podobne problemy.
Jared

W najgorszym wypadku, to nie naśladować przestarzałej .live()podejście; jednak zdolność kontrolowania delegacji jest z pewnością korzystna.
Dan Lugg

9

Wiem, że jest trochę za późno na odpowiedź, ale stworzyłem polifill dla metody .live (). Przetestowałem to w jQuery 1.11 i wydaje się, że działa całkiem dobrze. Wiem, że powinniśmy implementować metodę .on () tam, gdzie jest to możliwe, ale w dużych projektach, w których nie można przekonwertować wszystkich wywołań .live () na równoważne wywołania .on () z jakiegokolwiek powodu, poniższe mogą być praca:

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

Wystarczy dołączyć go po załadowaniu jQuery i przed wywołaniem live ().


5

.on () dotyczy jQuery w wersji 1.7 i nowszej. Jeśli masz starszą wersję, użyj tego:

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

8
OP mówi: „Używam jQuery v.1.7.1”
Selvakumar Arumugam

1
@ jfriend - dlaczego nie opublikować własnej odpowiedzi zamiast głosować na moją? Używam live () każdego dnia ze wszystkimi wersjami młodszymi niż 1.6 i działa dobrze. Widzę, że jesteś dobry w czytaniu dokumentacji, ale czasami bardziej pomaga w praktycznym zastosowaniu czegoś dla osoby. Działa .live (). Kropka.
Matt Cashatt

5
@MatthewPatrickCashatt - zamieściłem własną odpowiedź i nie głosowałem za twoją - nie idź na takie ślepe założenia. Wersja wcześniejsza niż 1.7 .delegate()działa znacznie lepiej niż .live()to, dlatego jQuery doc zaleca ją i przestaje działać .live(). Tak, .live()nadal działa, ale odpowiedzi tutaj na SO powinny zalecać lepszy sposób robienia rzeczy. Widziałem to 20 razy tutaj na SO. Jeśli .live()napiszesz kod tutaj na SO, zostanie on zanegowany (zwykle przeze mnie, chyba że jest z nim coś poważnie nie tak).
jfriend00

1
Nie przegłosowałem, ale chociaż .live()zdecydowanie działa nawet w wersji 1.7, powinieneś nadal używać .delegate()lub .on()ponieważ .live()był przestarzały z dobrego powodu. Dopóki zauważysz zmianę składni dwóch nowych funkcji, obie będą działać dobrze.
nnnnnn

1
@ jfriend00- Masz absolutną rację. Długi dzień. Przepraszam.
Matt Cashatt

3

Użyłem „live” w moim projekcie, ale jeden z moich znajomych zasugerował, że powinienem używać „on” zamiast live. A kiedy próbowałem go użyć, napotkałem problem taki jak ty.

Na moich stronach dynamicznie tworzę rzędy tabel przycisków i wiele rzeczy. ale kiedy używam magii, zniknęła.

Inne rozwiązania, takie jak używanie go jak dziecko, wywołują Twoje funkcje za każdym razem za każdym kliknięciem. Ale znajduję sposób, aby to się powtórzyło i oto rozwiązanie.

Napisz swój kod jako:

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

Call caller (); po utworzeniu obiektu na takiej stronie.

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

W ten sposób twoja funkcja jest wywoływana, gdy ma nie każde kliknięcie na stronie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.