Nehmen wir an, Sie arbeiten an einer Webanwendung in jQuery und sind damit beauftragt, ein Akkordeon zu schreiben, das den Bedürfnissen Ihrer Webanwendung entspricht. Sie beschließen, daraus ein Plugin zu machen. Auf diese Weise kann überall in dieser Anwendung, wo ein Akkordeon benötigt wird, dieses Plugin geladen und auf semantisches Markup angewendet werden, das bereit ist, ein Akkordeon zu werden. Dann ta-da, haben Sie ein schönes funktionierendes Akkordeon.
Nun verwendet ein anderer Entwickler Ihr Akkordeon und möchte in der Lage sein, Inhalte per Ajax in einen der Abschnitte des Akkordeons zu laden, aber nur, wenn dieser Abschnitt geöffnet wird. Gemeinsam beschließen Sie, dass Sie Ihren Code getrennt halten sollten. Die generische Funktionalität, wie ein Akkordeon funktioniert, sollte von Code getrennt sein, der für ein bestimmtes Akkordeon auf einer bestimmten Seite einer Anwendung spezifisch ist.
Callbacks, der traditionelle Weg
Ein möglicher Ansatz wäre, "Callbacks" in Ihr Plugin zu schreiben. Der andere Entwickler würde den Namen einer Funktion angeben, die ausgeführt werden soll, wenn bestimmte Aktionen auf diesem Akkordeon stattfinden. Das Aufrufen könnte dann so aussehen:
$(".accordion").accordion({
panelOpen: myPanelOpenCallback,
panelClose: myPanelCloseCallback;
});
Und sie hätten diese Callback-Funktionen selbst erstellt
function myPanelOpenCallback() {
// Do Ajax stuff
}
Dann würde das Plugin selbst diese Callbacks in seinen zugehörigen internen Funktionen berücksichtigen
$.fn.accordion = function(options) {
return this.each(function(i, el) {
var base = el;
base.init = function() {
// Do initialization stuff
};
base.openPanel = function(panel) {
// Open panel
// Do callback
options.panelOpen.call();
};
base.closePanel = function(panel) {
// Open panel
// Do callback
options.panelClose.call();
};
base.init();
});
};
Demo des Callback-Modells anzeigen
Benutzerdefinierte Ereignisse, ein besserer Weg
Nehmen wir nun an, ein dritter Entwickler wird hinzugezogen, und auch er möchte ein kleines Stück JavaScript schreiben, das auf das Öffnen eines Panels reagiert. Zur Veranschaulichung: In den Akkordeon-Panels befinden sich Einstellungen, und dieser Entwickler möchte diese Einstellungen jedes Mal speichern, wenn Schlüssel automatisch geöffnet oder geschlossen werden.
Nun befinden wir uns in einer interessanten Situation. Wir haben bereits unseren Callback für das Öffnen und Schließen von Akkordeon-Panels definiert. Im Callback-Modell müssen sich diese Entwickler also auf diesen Callback einigen und beide ihre Codes in diesem einen Callback ausführen. Das ist zwar keine große Sache, aber nun sind wir gezwungen, Code zu mischen, was vielleicht nicht ideal ist. Denken Sie daran, dass wir das Ganze mit der Trennung spezifischer Funktionalitäten begonnen haben.
Hier werden benutzerdefinierte Ereignisse super genial. Anstatt einen bestimmten Callback auszulösen, löst das Akkordeon-Funktionalitäts-Plugin ein benutzerdefiniertes Ereignis aus. Benutzerdefinierte Ereignisse sind wie jedes andere Ereignis (z. B. Klick), nur dass sie **nur** programmatisch deklariert und aufgerufen werden.
Zuerst sind die Callbacks weg, wir rufen das Akkordeon-Plugin einfach ohne sie auf
$(".accordion").accordion();
An der Stelle, an der wir zuvor die Callbacks aufgerufen haben, lösen wir nun unser benutzerdefiniertes Ereignis aus. Machen Sie sich im Grunde einen Namen, der Sinn ergibt (so wie Sie eine Funktion benennen).
// OUT
// options.panelOpen.call();
// IN
panel.trigger("panelOpen");
Nun können unsere anderen Entwickler ihre Dinge an dieses benutzerdefinierte Ereignis binden und ihr eigenes Ding machen.
$(".panel").on("panelOpen", function() {
// Developer 1: do Ajax stuff
});
// Meanwhile, in another part of town...
$(".panel").on("panelOpen", function() {
// Developer 2: do saving stuff
});
Hurra für Freiheit! Hurra für die Trennung von Funktionalitäten!
Meiner Meinung nach sind benutzerdefinierte Ereignisse rundum besser. Ich denke jedoch, dass sie etwas mehr Kommunikation erfordern. Wahrscheinlich müssen Sie irgendwo Kommentare verfassen, die erklären, welche benutzerdefinierten Ereignisse wann ausgelöst werden, und diese leicht auffindbar machen.
Demo des benutzerdefinierten Ereignismodells anzeigen
Weitere Informationen
Das dargestellte Szenario ist sehr einfach. Die folgenden beiden Artikel gehen viel tiefer auf benutzerdefinierte Ereignisse ein, einschließlich komplexerer Beispiele und weiterer Informationen zur Funktionsweise.
- Demystifying Custom Events in jQuery von Rebecca Murphey
- jQuery Special Events von Ben Alman
Noch besser wäre es, Ihre Ereignisse zu verschachteln.
Wobei das „open“-Ereignis unter „panel“ verschachtelt ist.
Guter Artikel Chris.
Benutzerdefinierte Ereignisse sind absolut genial.
Eine kleine Anmerkung: Manchmal ist es besser, .triggerHandler() anstelle von .trigger zu verwenden, um zu verhindern, dass sich das Ereignis im DOM-Baum nach oben ausbreitet.
Wenn Sie beispielsweise ein ereignisbasiertes Formularvalidierungstool schreiben, können Sie ein benutzerdefiniertes Ereignis namens ‚validate‘ erstellen und es sowohl an das Formular-Element als auch an alle Felder innerhalb des Formulars binden.
Wenn Sie nun .trigger(‚validate‘) auf dem Feld aufrufen würden, würde auch das Formular-Element ausgelöst. Wenn Sie .triggerHandler(‚validate‘) auf dem Feld verwenden, würde nur das Feld ausgelöst, nicht das Formular, das es enthält.
Es ist auch erwähnenswert, dass sowohl .trigger als auch .triggerHandler ein zusätzliches Array von Optionen akzeptieren, ähnlich wie die Argumente, die eine .call()-Funktion annehmen kann.
Auf jeden Fall gut zu sehen, dass Leute benutzerdefinierte Ereignisse gegenüber Callback-Funktionen bevorzugen!
Ich mag es, beide Methoden zu verwenden. Ein Callback bei der Erstellung würde einfach benutzerdefinierte Ereignisse im Hintergrund verwenden. Das löst teilweise den Bedarf an zusätzlicher Dokumentation.
Ich denke, qTip2 hat eine besonders gute Implementierung von benutzerdefinierten Ereignissen, wenn Sie ein reales Beispiel sehen möchten. Insbesondere die Verwendung des Ereignisobjekts. Die Verwendung dieses bietet mehr Flexibilität. Zum Beispiel
Zur Dokumentation des jQuery-Ereignisobjekts siehe http://api.jquery.com/category/events/event-object/
Ich benutze benutzerdefinierte Ereignisse sehr oft, ich hatte darüber einen Beitrag geschrieben: http://blog.imaginea.com/implementing-event-delegation-and-custom-events-in-javascript-using-jquery-prototypejs/
Diese erinnern mich an EventListener, mit der Ausnahme, dass man nicht sagen kann, wer auf was hört. Das finde ich etwas seltsam.
Nehmen wir an, 2 Buttons lösen beide ein „press“-Ereignis aus, wenn sie gedrückt werden.
Ein Button soll die Hintergrundfarbe des Bodys ändern, während der andere die Höhe des Divs ändern soll.
Wenn man nicht angeben kann, dass der Body nur auf einen Button hören soll, reagiert er, egal welcher Button gedrückt wird. Dasselbe gilt natürlich auch für das Div.
jQuery ist eine sehr nützliche JS-Skriptbibliothek. Die Verwendung hat mir bei der Entwicklung sehr geholfen.
Eigentlich stimme ich nicht zu. Dieser Ansatz ermutigt APIs, die über ihre Abhängigkeiten lügen.
Was meine ich damit? Ein Entwickler stolpert über eine Website, die Ihr
.accordion-Plugin verwendet. Das sieht er:Ohne den Quellcode dieses Plugins oder eine Art von Dokumentation anzusehen, kann der Entwickler nie wissen, dass das Plugin tatsächlich die besagten Ereignisse auslöst. Mit dem Callback-Ansatz jedoch
Hier hat das Plugin explizit erklärt, was es für seinen Betrieb benötigt. Die API ist **wahrhaftig**, sie lügt nicht, indem sie sagt: "Ich habe keine Funktionen, die mit mir mitgehen können, ich bin nur ein Akkordeon", sondern sagt jetzt: "Ich bin ein Akkordeon, *ich unterstütze Callback-Funktionen für
whenOpenedundwhenClosed, die aufgerufen werden, wenn diese Ereignisse eintreten*".Ich stimme dem zu. Chris, ich würde gerne hören – glaubst du, dass die Methode der benutzerdefinierten Ereignisse mehr Spaghetti-Code erzeugen würde? Ich meine damit: In Ihrer eigenen Datei (nicht im Plugin) viele scheinbar zufällige Listener für benutzerdefinierte Ereignisse (mit .on()) haben, ohne dass diese in einer Struktur liegen, die mit dem Plugin zusammenhängt (der Callback-Ansatz)? Ich sehe absolut den Vorteil, den Sie in Ihrem Artikel erwähnt haben (und danke für die Infos, übrigens – super genial), aber ich denke, wenn diese Methode in einem Projekt häufig verwendet wird, wird der Code sehr schwer zu verwalten sein.
Danke!
Während ich Ihnen teilweise zustimme, dass Sie API und Dokumentation erwähnen, würde ich von einem ordentlichen Plugin erwarten, dass es seine API in Form von Dokumentation auflistet. Daher sehe ich darin kein zu großes Problem.
Ich denke, wir können eine Kombination aus beidem verwenden. jQuery-Plugins haben eine Tradition der Verwendung von Callbacks, daher neige ich dazu, dabei zu bleiben.
Der Ereignisaufruf nach der Plugin-Initialisierung kann übersehen werden, während Callbacks in den Optionen nicht übersehen werden.
Eine schnelle Implementierung: http://jsbin.com/usaboz/2
Ich liebe das
Danke Chris ::D
Ein brillanter Artikel, benutzerdefinierte Ereignisse geben uns Entwicklern so viel mehr Freiheit. Danke, dass Sie diese Informationen geteilt haben, ich werde sie an einige Freunde weiterleiten, von denen ich weiß, dass sie sie auch gerne lesen werden.
Eine kurze Nachricht an Chris bezüglich dieses Kommentarformulars von Ihnen. Während ich das Aussehen und Layout dieses Kommentarformulars liebe, mag ich die Symbole, die Sie verwendet haben, um zu erklären, wofür jedes Textfeld ist, nicht so sehr. Ich musste NACHDENKEN, was wohin gehört... Die Symbole für Name und E-Mail habe ich gut verstanden, aber beim dritten Symbol für die Website-URL hatte ich Schwierigkeiten zu raten. Ich weiß, dass Sie ein großer Verfechter der Barrierefreiheit Ihrer Blogs sind, daher dachte ich, ich sollte Sie auf dieses kleine Problem aufmerksam machen, da ich sicher bin, dass andere das gleiche Problem hatten. Selbst wenn Sie nur einen sehr einfachen Hover-Popup für die Symbole hinzufügen würden, würde das das Problem lösen. Persönlich würde ich das dritte URL-Symbol in ein Kette/Link-Symbol ändern, da jeder das verstehen würde.
Ich hoffe, es ist Ihnen nicht unangenehm, dass ich das hier poste, ich weiß, es hat nichts direkt mit diesem Artikel zu tun, also wenn Sie das gelesen haben, ist es mir egal, wenn Sie es löschen. Auch, falls Sie doch eine Hover-Beschreibung für jedes Textfeld haben und es tatsächlich mein eigener Browser ist, der schuld ist, für Ihre Referenz benutze ich Firefox Version 3.6.
Wenn Sie einen modernen Webbrowser verwenden würden, würden Sie den Vorschautext in den Textfeldern sehen. Wenn Sie sehbehindert wären, würden Sie den beschreibenden Text hören, der mit den Feldern verbunden ist. Ich denke, es ist an der Zeit, dass Sie sich aktualisieren.
Wenn Sie einen modernen Webbrowser verwenden würden, würden Sie den Vorschautext in den Textfeldern sehen. Wenn Sie sehbehindert wären, würden Sie den beschreibenden Text hören, der mit den Feldern verbunden ist. Ich denke, es ist an der Zeit, dass Sie sich aktualisieren.
-----
^ das ist eine unhöfliche und mürrische Antwort auf eine berechtigte Beschwerde über die Benutzeroberfläche, insbesondere da Firefox 3.6 EIN gültiger Browser ist und nicht jeder in der Lage ist, einfach zu "upgraden".
Der Text verschwindet, wenn das Feld den Fokus hat. Wenn Sie sich also nicht gemerkt haben, welcher Text vorher da war, wissen Sie nicht, was Sie dort eingeben sollen, und das "Symbol" hilft überhaupt nicht.
Keine große Sache, da dieses Feld nicht erforderlich ist, aber warum sich die Mühe machen??
Die Widget-Factory von jQuery UI unterstützt das Auslösen von Ereignissen als Teil des Widgets. Sie erlaubt auch das Binden der Ereignisse als Teil des Initialisierungsobjekts.
Diese sind absolut genial! Ich spiele gerade mit benutzerdefinierten Ereignissen.
Benutzerdefinierte Ereignisse und modulare, erweiterbare Codes sind alles ziemlich geniale Dinge... Ich wünschte nur, die Leute würden erkennen, dass sie gerade erst beginnen, Funktionen und Prinzipien kennenzulernen, die es in MooTools seit mehr als 6 Jahren gibt – this.fireEvent('customEventName'). Wenn Sie einen noch flexibleren, erweiterbaren Code wünschen, der alle im Artikel genannten Funktionen (und noch viel mehr) hat, ermutige ich Sie, MooTools auszuprobieren. Es ist in so vielerlei Hinsicht einfach jenseits von JQuerys begrenztem DOM-zentrierten Umfang (ich habe kürzlich ein ganzes Node.js-Framework damit erstellt, weil es auch auf der Serverseite rockt!).
Wollte nur sagen: Frohe Weihnachten an alle und ein glückliches neues Jahr.
Was?
Chris! Ich mochte Ihre Methode – wenn man mit der Maus über den Titel fährt, wird auch der "Weiterlesen"-Link angesteuert. Können Sie mir schreiben, wie das gemacht wird? Danke im Voraus
Ich bin etwas verwirrt. Das funktioniert doch nur, wenn die Komponente so programmiert ist, dass sie die benutzerdefinierten Ereignisse auslöst, oder?
Danke.