Różnica między funkcjami jQuery „click”, „bind”, „live”, „delegate”, „trigger” i „on” (z przykładem)?

139

Przeczytałem dokumentację każdej funkcji na jQuery official website, ale nie ma takich zestawień porównawczych między poniższymi funkcjami:

$().click(fn)
$().bind('click',fn)
$().live('click',fn)
$().delegate(selector, 'click', fn)
$().trigger('click') // UPDATED
$().on('click', selector ,fn); // more UPDATED

Unikaj linków referencyjnych.

Jak dokładnie działają wszystkie powyższe funkcje i które powinny być preferowane w jakiej sytuacji?

Uwaga: Jeśli istnieją inne funkcje, które mają tę samą funkcjonalność lub mechanizm, prosimy o wyjaśnienie.

Aktualizacja

Widziałem też $.triggerfunkcję. Czy działa podobnie do powyższych funkcji?

Więcej aktualizacji

Teraz .onjest dodany w wersji 1.7 i myślę, że ten w jakiś sposób spełnia wszystkie powyższe wymagania funkcji razem.

diEcho
źródło
3
@I Podobnie jak PHP, czasami ludzie głosują w dół, jeśli nie uważają, że jest to pytanie, na które nie można odpowiedzieć w instrukcji lub wydaje się, że jest to pytanie domowe. nie martw się, inne osoby zagłosują na to, jeśli uznają to za przydatne.
typoneerror
@ Typeoneerror - Dzięki za wsparcie, przeczytałem już instrukcję, a kiedy nie zrozumiałem wyraźnej różnicy, piszę tutaj.
diEcho
3
@I Like PHP - Edytowałem pytanie, aby trochę uporządkować ... jest to często zadawane, ale rzadko w ten sposób, łatwo może być cennym zasobem, który można znaleźć w Google. Zgadzam się, że wpis na wiki na temat czegoś takiego byłby bardzo pomocny. Widzę zamieszanie wokół tego, zwłaszcza w przypadku .live()i .delegate()prawie codziennie +1 za całkowicie poprawne pytanie.
Nick Craver
@Nick Craver Dzięki za edycję, właściwie jestem zły po angielsku (lol). czy jest jakaś instrukcja / odniesienie, na temat którego możemy opublikować pytanie SO. ot to tylko wynikało z doświadczenia
diEcho
@I Like PHP - to po trochu jedno i drugie, tutaj jest świetne, wszechstronne FAQ dla SO: meta.stackexchange.com/questions/7931 Jeśli chodzi o wyrażenia / komentarze, po prostu zaczynasz się uczyć, co pasuje i jest najlepszym sposobem przekazuj swoje myśli, kod> jakikolwiek opis czasami, używając odpowiedniego słowa kluczowego, odpowiednio tagując, po prostu przychodzi im dłużej tu jesteś. Przypuszczam, że wiele plakatów poprawia się z czasem. Jeśli chodzi o twoją edycję, .trigger()po prostu wywołuje procedurę obsługi zdarzeń ... Poniżej dodam opis do mojej odpowiedzi.
Nick Craver

Odpowiedzi:

162

Zanim to przeczytasz, wyciągnij listę wydarzeń na inną stronę, sam interfejs API jest niezwykle pomocny, a wszystko, o czym rozmawiam poniżej, jest bezpośrednio połączone z tą stroną .

Po pierwsze, .click(function)jest dosłownie skrótem .bind('click', function), są one równoważne. Użyj ich podczas wiązania procedury obsługi bezpośrednio z elementem , na przykład:

$(document).click(function() {
  alert("You clicked somewhere in the page, it bubbled to document");
});

Jeśli ten element zostanie wymieniony lub wyrzucony, tego modułu obsługi już nie będzie. Również elementy, których nie było, gdy ten kod był uruchamiany w celu dołączenia procedury obsługi (np. Selektor znalazł go wtedy), nie otrzymają funkcji obsługi.

.live()i .delegate()są podobnie powiązane, w .delegate()rzeczywistości używają .live()wewnętrznie, oboje nasłuchują wydarzeń, aby bąbelkować. Działa to w przypadku nowych i starych elementów , w ten sam sposób bąbelkują wydarzenia. Używasz ich, gdy elementy mogą się zmienić, np. Dodając nowe wiersze, elementy listy itp. Jeśli nie masz rodzica / wspólnego przodka, który pozostanie na stronie i nie zostanie w żadnym momencie zastąpiony, użyj w .live()ten sposób:

$(".clickAlert").live('click', function() {
  alert("A click happened");
});

Jeśli jednak masz gdzieś element nadrzędny, który nie jest zastępowany (więc jego procedury obsługi zdarzeń nie idą do widzenia), powinieneś obsłużyć go w .delegate()następujący sposób:

$("#commonParent").delegate('.clickAlert', 'click', function() {
  alert("A click happened, it was captured at #commonParent and this alert ran");
});

Działa to prawie tak samo, jak .live(), ale zdarzenie bąbelkuje mniej razy przed przechwyceniem i wykonaniem programów obsługi. Innym typowym zastosowaniem obu tych sposobów jest powiedz, że twoja klasa zmienia się w elemencie, nie pasując już do selektora, którego pierwotnie użyłeś ... z tymi metodami selektor jest oceniany w czasie zdarzenia , jeśli pasuje, program obsługi działa. . więc element już nie pasujący do selektora ma znaczenie, nie będzie już wykonywany. Dzięki .click()jednak obsługi zdarzeń jest związana bezpośrednio na elemencie DOM, fakt, że nie równą selektor użyto go znaleźć nie ma znaczenia ... zdarzenie jest związany i to pobyt aż element ten nie ma, lub opiekun jest usuwany za pośrednictwem .unbind().

Jeszcze innym powszechnym zastosowaniem .live()i .delegate()jest wydajność . Jeśli masz do czynienia z wieloma elementami, dołączenie modułu obsługi kliknięcia bezpośrednio do każdego elementu jest kosztowne i czasochłonne. W takich przypadkach bardziej ekonomiczne jest skonfigurowanie pojedynczego modułu obsługi i pozwolenie bąbelkowi na wykonanie pracy, spójrz na to pytanie, gdzie spowodowało to ogromną różnicę , jest to dobry przykład aplikacji.


Wyzwalanie - dla zaktualizowanego pytania

Dostępne są 2 główne funkcje wyzwalające obsługę zdarzeń, które należą do tej samej kategorii „Załącznik programu obsługi zdarzeń” w interfejsie API , są to .trigger()i .triggerHandler(). .trigger('eventName')ma wbudowane pewne skróty do typowych zdarzeń, na przykład:

$().click(fn); //binds an event handler to the click event
$().click();   //fires all click event handlers for this element, in order bound

Listę zawierającą te skróty można wyświetlić tutaj .

Jeśli chodzi o różnicę, .trigger()uruchamia procedurę obsługi zdarzenia (ale przez większość czasu nie jest to domyślna akcja, np. Umieszczenie kursora w odpowiednim miejscu w klikniętym miejscu <textarea>). Powoduje, że programy obsługi zdarzeń występują w kolejności, w jakiej zostały powiązane (tak jak zdarzenie natywne), uruchamia natywne akcje zdarzenia i tworzy kopułę DOM.

.triggerHandler()ma zwykle inny cel, tutaj po prostu próbujesz odpalić powiązane procedury obsługi, nie powoduje to uruchomienia zdarzenia natywnego, np. przesłania formularza. Nie tworzy bąbelków w modelu DOM i nie można go łączyć w łańcuchy (zwraca cokolwiek zwraca procedurę obsługi zdarzenia ostatniego powiązania dla tego zdarzenia). Na przykład, jeśli chcesz wyzwolić focuszdarzenie, ale tak naprawdę nie skupiasz się na obiekcie, po prostu chcesz, aby kod, z .focus(fn)którym jesteś powiązany, działał, to zrobiłoby to, ale .trigger()zrobiłby to, a także faktycznie skupiłby element i pojawił się.

Oto przykład z prawdziwego świata:

$("form").submit(); //actually calling `.trigger('submit');`

Spowoduje to uruchomienie wszystkich programów obsługi przesyłania, na przykład wtyczki walidacji jQuery , a następnie spróbuje przesłać plik <form>. Jeśli jednak chcesz tylko sprawdzić poprawność, ponieważ jest ona podłączona przez submitmoduł obsługi zdarzeń, ale nie przesyłaj <form>później, możesz użyć .triggerHandler('submit'), na przykład:

$("form").triggerHandler('submit');

Wtyczka zapobiega przesłaniu formularza przez program obsługi przez zbombardowanie, jeśli sprawdzenie poprawności nie przejdzie, ale w przypadku tej metody nie obchodzi nas, co robi. Niezależnie od tego, czy nastąpiło przerwanie, czy nie, nie próbujemy przesłać formularza, chcieliśmy po prostu uruchomić go, aby ponownie zweryfikował i nie robił nic więcej. ( Zastrzeżenie: jest to zbędny przykład, ponieważ .validate()wtyczka zawiera metodę, ale jest to przyzwoita ilustracja zamiaru)

Nick Craver
źródło
Bardzo dokładny. Jedna mała poprawka: triggernie uruchamia rodzimego zdarzenia. Przez natywny rozumiem zdarzenie symulowane za pomocą fireEvent(IE) lub dispatchEvent(w3c).
Crescent Fresh
@Crescent - zaktualizowany, aby był mniej niejednoznaczny, miałem na myśli, że uruchamia natywne akcje wydarzenia , takie jak przesyłanie formularzy, śledzenie linków itp ... mam nadzieję, że aktualizacja jest bardziej przejrzysta :)
Nick Craver
@Nic z tego, co czytam, wygląda na to, że twoje podejście live()różni się od tego, które mi dałeś: stackoverflow.com/questions/3981762/… Czy „waga” nadal stanowi problem podczas używania live()?
Yahel,
@yahelc - Tak, oczywiście ... ta odpowiedź polega na ścisłym porównaniu opcji obsługi zdarzeń i ich określonego celu. Koszt wagi w porównaniu z liczbą początkowych powiązań w porównaniu z dodawaniem czegokolwiek dynamicznie w porównaniu z początkowym selektorem to nadal ważne kwestie. Jeśli jesteś struktura strony nie jest to duży ty nie masz , że wiele wydarzeń wtedy jesteś w porządku ... koncern na wadze jest wprost proporcjonalna do wielkości / głębokości swojej struktury i liczby zdarzeń (z typ .live()połączenia, którego nasłuchuje, np. click), który jest generowany, ponieważ uruchamia selektory dla każdego z nich.
Nick Craver
1
w jQuery 1.7 live () jest przestarzałe na rzecz $ (document) .on ().
Synchro
28

Pierwsze dwa są równoważne.

// The following two statements do the same thing:
$("blah").click( function() { alert( "Click!" ); } );
$("blah").bind( "click", function() { alert( "Click!" ); } ); 

Drugiego można jednak użyć do powiązania z więcej niż jednym zdarzeniem w tym samym czasie, określając kilka nazw zdarzeń oddzielonych spacjami:

$("blah").bind( "click mouseover mouseout", function() { alert( "Click! Or maybe mouse moved." ); } ); 

.liveMetoda jest bardziej interesująca. Rozważmy następujący przykład:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").click( function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

Po wykonaniu drugiej linii skryptu drugie łącze również będzie miało klasę CSS „myLink”. Ale nie będzie miał obsługi zdarzeń, ponieważ nie miał klasy w momencie dołączania zdarzenia.

Rozważmy teraz, że chciałeś, aby było odwrotnie: za każdym razem, gdy łącze z klasą „myLink” pojawia się gdzieś na stronie, chcesz, aby automatycznie posiadało tę samą procedurę obsługi zdarzeń. Jest to bardzo częste, gdy masz jakieś listy lub tabele, w których dodajesz wiersze lub komórki dynamicznie, ale chcesz, aby wszystkie zachowywały się w ten sam sposób. Zamiast za każdym razem zadawać sobie trud związany z przypisywaniem obsługi zdarzeń od nowa, możesz skorzystać z .livemetody:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").live( "click", function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

W tym przykładzie drugie łącze również otrzyma program obsługi zdarzeń, gdy tylko otrzyma klasę „myLink”. Magia! :-)

Oczywiście nie jest to takie dosłowne. To, co .livetak naprawdę robi, to dołączenie handlera nie do samego określonego elementu, ale do samego katalogu głównego drzewa HTML (element „body”). Wydarzenia w DHTML mają tę zabawną cechę „bulgotania”. Rozważ to:

<div> <a> <b>text</b> </a> </div>

Jeśli klikniesz „tekst”, najpierw element <b> otrzyma zdarzenie „kliknięcie”. Następnie element <a> otrzyma zdarzenie „kliknięcie”. Następnie element <div> otrzyma zdarzenie „kliknięcie”. I tak dalej - aż do elementu <body>. I to jest miejsce, w którym jQuery złapie zdarzenie i sprawdzi, czy są jakieś "na żywo" procedury obsługi, które dotyczą elementu, który spowodował zdarzenie. Schludny!

I wreszcie .delegatemetoda. Po prostu bierze wszystkie elementy potomne twojego elementu, które są zgodne z podanym selektorem i dołącza do nich "żywą" procedurę obsługi. Spójrz:

$("table").delegate( "td", "click", function() { alert( "Click!" ); } );

// Is equivalent to:
$("table").each( function() {
    $(this).find( "td" ).live( "click", function() { alert( "Click!" ); } );
} );

Pytania?

Fyodor Soikin
źródło
Aby być dokładnym, .live()wiąże się z documentnie <body>:) Możesz obejrzeć demo tutaj, po prostu podnieś konsolę, aby sprawdzić: jsfiddle.net/aJy2B
Nick Craver
3
Wygodniej było to wyjaśnić w ten sposób. :-)
Fyodor Soikin
4
W porządku, jeśli chodzi o część „body”, ale „aż do elementu <body>” jest błędne, zdarzenia nadal się tam toczą i nie jest to miejsce, w którym .live()mieszkają handlowcy, jest powyżej, na document:) Możesz zobaczyć demo tego tutaj: jsfiddle.net/S2VBX
Nick Craver
8

Od wersji jQuery 1.7 metoda .live () była przestarzała. Jeśli używasz wersji jQuery <1.7, to oficjalnie zaleca się używanie .delegate () zamiast .live ().

.live () został teraz zastąpiony przez .on ().

Najlepiej przejść bezpośrednio do witryny jQuery, aby uzyskać więcej informacji, ale oto aktualne wersje metody .on ():

.on( events [, selector] [, data], handler(eventObject) )
.on( events-map [, selector] [, data] )

http://api.jquery.com/on/

Jonathan Tonge
źródło
2

$().click(fn)i $().bind('click', fn)są identyczne na pierwszy rzut oka, ale $.bindwersja jest mocniejsza z dwóch powodów:

  1. $().bind()umożliwia przypisanie jednego modułu obsługi do wielu zdarzeń, na przykład $().bind('click keyup', fn).
  2. $().bind()obsługuje zdarzenia w przestrzeni nazw - potężna funkcja, jeśli chcesz usunąć (odłączyć) tylko niektóre programy obsługi zdarzeń, z którymi element jest powiązany - przeczytaj więcej w sekcji Zdarzenia w przestrzeni nazw .

Na żywo vs delegat: odpowiedź na to pytanie znajduje się już w innych odpowiedziach.

fbuchinger
źródło
1

W tym miejscu może pomóc czytanie interfejsu API. Jednak wiem z góry, więc możesz nadal być leniwy (yay!).

$('#something').click(fn);
$('#something').bind('click',fn);

Tutaj nie ma różnicy (o czym wiem). .clickjest po prostu wygodną / pomocniczą metodą.bind('click'

// even after this is called, all <a>s in
// <div class="dynamic_els"> will continue
// to be assigned these event handlers

$('div.dynamic_els a').live(‘click’,fn);

Jest to zupełnie inne, ponieważ .livedodaje zdarzenia do selektora, który przekazujesz (którego nie masz tutaj) i kontynuuje przeglądanie DOM, gdy węzły są wstawiane / usuwane

$('#some_element').delegate('td','click',fn);

Różni się to tylko ze względu na sposób, w jaki przypisujesz programy obsługi zdarzeń. .delegatekoncentruje się na propagowaniu zdarzeń DOM. Podstawową zasadą jest to, że każde zdarzenie przechodzi w górę przez drzewo DOM, aż dotrze do elementu głównego ( documentlub windowlub <html>lub <body>, nie pamiętam dokładnie).

Tak czy inaczej, wiążesz onclickprocedurę obsługi ze wszystkimi <td>s wewnątrz $('#some_element')(musisz określić selektor, chociaż możesz powiedzieć $(document)). Po kliknięciu jednego z jego elementów podrzędnych zdarzenie przechodzi do <td>. Następnie możesz wyodrębnić element źródłowy zdarzenia (co jQuery robi za Ciebie automagicznie).

Jest to przydatne, gdy jest mnóstwo elementów i masz tylko kilka (lub jeden centralny) punkt, przez który te zdarzenia przejdą. Oszczędza to wysiłek przeglądarki i pamięć, aby skonsolidować te programy obsługi zdarzeń w mniejszą liczbę obiektów.

Dan Beam
źródło
1
.live() działa również na bulgotanie zdarzeń, w rzeczywistości .delegate()jest opakowaniem dla .live(), po prostu dodaje kontekst i wiąże się z elementem innym niż documentprzechwytywanie bąbelków. Myślę, że twoje zrozumienie, jak działają programy obsługujące bulgotanie, jest nieco nierealne (jest to najczęściej niezrozumiany aspekt jQuery 1.4). Procedura obsługi znajduje się tylko na elemencie, z którym jest powiązany, więc niezależnie od elementu, który wywołałeś .delegate(), lub documentw przypadku .live(), gdy zdarzenie tam przechodzi, sprawdza cel, aby zobaczyć, czy pasuje do selektora, a jeśli tak, jest wykonywany.
Nick Craver