jQuery .live () vs .on () Methode zum Hinzufügen eines Klickereignisses nach dem Laden von dynamischem HTML

216

Ich verwende jQuery v.1.7.1, wo die .live () -Methode anscheinend veraltet ist.

Das Problem, das ich habe, ist, dass beim dynamischen Laden von HTML in ein Element mit:

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

Wenn ich danach versuche, ein Klickereignis hinzuzufügen, wird das Ereignis mit keiner der folgenden Methoden registriert:

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

oder

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

Was ist der richtige Weg, um diese Funktionalität zu erreichen? Es scheint nur mit .live () für mich zu funktionieren, aber ich sollte diese Methode nicht verwenden. Beachten Sie, dass #child ein dynamisch geladenes Element ist.

Vielen Dank.

Sean Thoman
quelle
25
Warum sagst du "angeblich veraltet" ? Glauben Sie den Dokumenten nicht?
6
Es ist angeblich nicht veraltet: Es ist veraltet. Wenn Sie sich das jQuery-Dokument.live() ansehen, erfahren Sie, wie Sie vorhandene Verwendungen von .live()zu verwenden .delegate()oder umschreiben .on()(je nachdem, ob Sie Version 1.7+ verwenden oder nicht). Beachten Sie jedoch, dass, wenn Sie einen Handler mit .click()"after" hinzufügen, wie Sie bereits erwähnt haben, dh nach dem dynamischen Laden von Elementen, dies funktionieren sollte - das einzige Problem besteht darin, .click() vor dem dynamischen Laden von Elementen eine Zuweisung vorzunehmen.
nnnnnn
Ich habe den Wortlaut in "anscheinend" geändert, da ich das im Grunde genommen habe. Wie auch immer, ich verstehe jetzt, dass offensichtlich, da das .load () -Ereignis asynchron ist, das # child-Element nur im Success-Handler zuverlässig erkannt werden konnte, was sinnvoll ist.
Sean Thoman

Antworten:

606

Wenn der Click-Handler für ein Element funktionieren soll, das dynamisch geladen wird, legen Sie den Event-Handler für ein übergeordnetes Objekt fest (das nicht dynamisch geladen wird) und geben ihm einen Selektor, der Ihrem dynamischen Objekt wie folgt entspricht:

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

Der Ereignishandler wird an das #parentObjekt angehängt, und jedes Mal, wenn ein Klickereignis auf das Objekt sprudelt, das seinen Ursprung hat #child, wird Ihr Klickhandler ausgelöst. Dies wird als delegierte Ereignisbehandlung bezeichnet (die Ereignisbehandlung wird an ein übergeordnetes Objekt delegiert).

Dies geschieht auf diese Weise, da Sie das Ereignis an das #parentObjekt anhängen können, auch wenn das #childObjekt noch nicht vorhanden ist. Wenn es jedoch später vorhanden ist und angeklickt wird, sprudelt das Klickereignis zum #parentObjekt und zeigt an, dass es von #childund stammt Es gibt einen Ereignishandler zum Klicken #childund Auslösen Ihres Ereignisses.

jfriend00
quelle
23
Tolle Erklärung! Ich habe noch nie gelungen, meinen Kopf herum wickeln live()vs. on()aber heute habe ich beschlossen , noch einmal zu versuchen, und Ihre Erklärung enthüllen sofort , was ich die ganze Zeit gefehlt hatte. Vielen Dank!
MikeSchinkel
6
Eine Million Ups . Ich habe angefangen, Knockout zu verwenden, bevor mir klar wurde, dass dies in jQuery für dynamisch erstellte Kinder möglich ist. Vielen Dank.
Brock Hensley
9
Sie sollten überlegen, ein Buch oder etwas anderes zu schreiben: Ihr kleiner Text war für mich hilfreicher als die ganze Seite in den jQuery-Dokumenten zu « on () ». Vielen Dank!
Cholesterin
@ jfriend00 wissen Sie zufällig, wie wir denselben Prozess auf eine Hover-Situation ohne Hover anwenden können? Gibt es eine Quelle, die darüber spricht?
Klewis
@blackhawk - Siehe diese Antwort . Sie können für die Register mouseenterund mouseleaveEreignisse und Test innerhalb des Handlers , die ein ausgelöst wurde. Das Pseudo-Hover-Ereignis von jQuery ist bei der Delegierung nicht verfügbar.
jfriend00
33

Versuche dies:

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

Aus der $.on()Dokumentation:

Ereignishandler sind nur an die aktuell ausgewählten Elemente gebunden. Sie müssen zum Zeitpunkt des Aufrufs Ihres Codes auf der Seite vorhanden sein .on().

Ihr #childElement existiert nicht, wenn Sie es aufrufen $.on(), daher ist das Ereignis nicht gebunden (im Gegensatz zu $.live()). #parentJedoch tut exist, so verbindlich das Ereignis , dass in Ordnung ist.

Das zweite Argument in meinem obigen Code fungiert als 'Filter', der nur ausgelöst wird, wenn das Ereignis bis #parentvon sprudelt #child.

Bojangles
quelle
Wenn ich die $ .on () -Methode nach der $ .load () -Methode aufrufe, warum würde das # child-Element dann zu diesem Zeitpunkt nicht existieren?
Sean Thoman
6
@SeanThoman - Sie müssten es vom Success-Handler der .load()Methode aufrufen - nicht vom Code nach der .load()Methode. #childEs ist nur bekannt, dass es geladen wird, wenn der Success-Handler tatsächlich ausgeführt wird und nicht vorher.
jfriend00
Und selbst dann bedeutet die Zeit, die benötigt wird, um die Daten, die Sie zurück in das DOM erhalten haben, einzufügen, dass möglicherweise keine Verbindung hergestellt wird. Ich habe in letzter Zeit viele Single-Page-App-Arbeiten durchgeführt und mein Standard ist var $ body = $ ('body'); $ body.on ("event", ".element / # class", Funktion (e) {}); für alles. 1 Wahlschalter. Keine Sorge, was geladen ist oder nicht.
Lupos
21

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

EDIT: Ich gebe ein bisschen mehr Informationen darüber, wie das funktioniert, weil ... Worte. In diesem Beispiel platzieren Sie einen Listener für das gesamte Dokument.

Wenn Sie clickmit einem oder mehreren Elementen übereinstimmen .selector, sprudelt das Ereignis bis zum Hauptdokument - solange es keine anderen Listener gibt, die die event.stopPropagation()Methode aufrufen -, wodurch das Sprudeln eines Ereignisses zu übergeordneten Elementen übertroffen wird.

Anstatt an ein bestimmtes Element oder eine bestimmte Gruppe von Elementen zu binden, warten Sie auf Ereignisse, die von Elementen stammen, die dem angegebenen Selektor entsprechen. Dies bedeutet, dass Sie einmal einen Listener erstellen können, der automatisch den aktuell vorhandenen Elementen sowie allen dynamisch hinzugefügten Elementen entspricht.

Dies ist aus mehreren Gründen sinnvoll, einschließlich Leistung und Speichernutzung (in großen Anwendungen).

BEARBEITEN:

Offensichtlich ist das nächstgelegene übergeordnete Element, das Sie abhören können, besser, und Sie können jedes Element anstelle von verwenden document, solange sich die untergeordneten Elemente, auf die Sie Ereignisse überwachen möchten, in diesem übergeordneten Element befinden ... aber das hat wirklich nichts zu tun mit der Frage.

L422Y
quelle
23
Er versuchte es $(element).on(...). Das ist $(document).on(...,element,...). Verschiedene Tiere.
CHao
@ArnoldRoa ja, bessere Leistung. Sie haben keinen Listener für mehrere untergeordnete Elemente, müssen den Listener nicht erneut anwenden, wenn das DOM geändert wird, und Ereignisse sprudeln standardmäßig durch das DOM. Einmal ausführen und jedes Kind, das dem Selektor entspricht, löst beim Klicken die angegebene Funktion aus.
L422Y
@ L422Ys Kommentar hier ist sehr irreführend. Wenn Sie neugierig auf die Auswirkungen auf die Leistung sind, werfen Sie einen Blick auf @ jfriend00s Kommentar zu @ Jareds Antwort
Gust van de Wal
@GustvandeWal Wie ist es irreführend? Wenn Sie hundert $ (this) .on (...) ausgeben, anstatt einmal auf ein übergeordnetes Element auf ein Ereignis zu warten, ist es wesentlich leistungsfähiger.
L422Y
Sie sprechen nur über das Anhängen der Ereignisse. Bei realen Leistungsengpässen werden zu viele Hörer ausgelöst (wie die, die Sie delegieren), und nicht zu viele Elemente, an die ein Ereignis angehängt werden muss.
Gust van de Wal
12

Das Äquivalent von .live () in 1.7 sieht folgendermaßen aus:

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

Beobachten Sie das Dokument grundsätzlich auf Klickereignisse und filtern Sie sie nach #child.

Jared
quelle
Denn so hängt der Ereignishandler das Dokument an (wie es der Fall .live()ist).
CHao
17
Ein Grund, der .live()jetzt veraltet ist, ist, dass es schlecht ist, alle Live-Ereignishandler auf das Dokumentobjekt zu setzen. Die Dinge können sich wirklich sehr, sehr verlangsamen. Ereignisse müssen nicht nur bis zum Dokument sprudeln, sondern Sie müssen möglicherweise viele Ereignishandler für das Dokumentobjekt durchsehen. Der Hauptvorteil .on()besteht darin, dass Sie es an ein übergeordnetes Objekt anhängen können, das viel näher am tatsächlichen Objekt liegt, und die Leistung drastisch verbessern können. Also ... Ich würde NICHT empfehlen, .on()mit dem Dokumentobjekt zu verwenden. Es ist viel besser, ein näheres übergeordnetes Objekt auszuwählen.
jfriend00
Danke für die Klarstellung. Für das, was es wert ist, wurde die Leistung von Ereignissen mit on () erheblich verbessert, so dass es weniger ein Problem sein sollte als früher. Wenn Sie eine Verbindung zu einem übergeordneten Element herstellen, würde ich davon ausgehen, dass es sich um ein übergeordnetes Element handeln muss, das in einem Dokument bereit ist, da sonst ähnliche Probleme auftreten.
Jared
Im schlimmsten Fall ahmt dies den veralteten .live()Ansatz nach; Die Möglichkeit, die Delegierung zu steuern, ist jedoch sicherlich von Vorteil.
Dan Lugg
9

Ich weiß, dass es etwas spät für eine Antwort ist, aber ich habe eine Polyfüllung für die .live () -Methode erstellt. Ich habe es in jQuery 1.11 getestet und es scheint ziemlich gut zu funktionieren. Ich weiß, dass wir die .on () -Methode wo immer möglich implementieren sollen, aber in großen Projekten, in denen es nicht möglich ist, alle .live () -Aufrufe aus irgendeinem Grund in die entsprechenden .on () -Aufrufe zu konvertieren, kann dies folgendermaßen sein Arbeit:

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

Fügen Sie es einfach hinzu, nachdem Sie jQuery geladen haben und bevor Sie live () aufrufen.

NSV
quelle
5

.on () ist für jQuery Version 1.7 und höher. Wenn Sie eine ältere Version haben, verwenden Sie diese:

$("#SomeId").live("click",function(){
    //do stuff;
});
Matt Cashatt
quelle
8
OP sagt "Ich benutze jQuery v.1.7.1"
Selvakumar Arumugam
1
@ jfriend - warum nicht deine eigene Antwort posten, anstatt meine herunterzustimmen? Ich benutze live () jeden Tag mit allen Versionen jünger als 1.6 und es funktioniert gut. Ich kann sehen, dass Sie gut darin sind, Dokumentationen zu lesen, aber manchmal ist es hilfreicher, etwas für eine Person in die Praxis umzusetzen. .live () funktioniert. Zeitraum.
Matt Cashatt
5
@MatthewPatrickCashatt - Ich habe meine eigene Antwort gepostet und Ihre nicht abgelehnt - machen Sie keine so blinden Annahmen. Pre 1.7 bietet .delegate()eine viel bessere Leistung als .live()das, weshalb das jQuery-Dokument dies empfiehlt und ablehnt .live(). Ja, .live()funktioniert immer noch, aber Antworten hier auf SO sollten die bessere Vorgehensweise empfehlen. Ich habe das 20 Mal hier auf SO gesehen. Wenn Sie .live()hier auf SO eine Postleitzahl posten, wird diese herabgestuft (normalerweise nicht von mir, es sei denn, es stimmt etwas anderes nicht)).
jfriend00
1
Ich habe nicht abgelehnt, aber obwohl es .live()definitiv auch in Version 1.7 funktioniert, sollten Sie es trotzdem verwenden .delegate()oder .on()weil .live()es aus gutem Grund veraltet war. Solange Sie die Änderung der Syntax für die beiden neueren Funktionen beachten, funktioniert beides einwandfrei.
nnnnnn
1
@ jfriend00- Du hast absolut recht. Langer Tag. Entschuldigen Sie.
Matt Cashatt
3

Ich habe in meinem Projekt "live" verwendet, aber einer meiner Freunde schlug vor, "on" anstelle von "live" zu verwenden. Und als ich versuchte, das zu nutzen, hatte ich ein Problem wie Sie.

Auf meinen Seiten erstelle ich dynamisch Schaltflächen-Tabellenzeilen und viele Dom-Sachen. aber wenn ich die Magie benutze, verschwand sie.

Die anderen Lösungen wie "Verwenden Sie es wie ein Kind" rufen Ihre Funktionen jedes Mal bei jedem Klick auf. Aber ich finde einen Weg, es wieder möglich zu machen und hier ist die Lösung.

Schreiben Sie Ihren Code als:

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

Anrufer anrufen (); nachdem Sie Ihr Objekt auf der Seite wie folgt erstellt haben.

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

Auf diese Weise wird Ihre Funktion aufgerufen, wenn nicht jeder Klick auf die Seite erfolgen soll.

Coderx07
quelle