JavaScript-Events Von Grund auf

Fast alles, was Sie in JavaScript tun, sollte beginnen, wenn etwas passiert: Der Benutzer klickt auf eine Schaltfläche, schwebt über einem Menü, drückt eine Taste, Sie bekommen die Idee. Mit Bibliotheken wie jQuery ist das ziemlich einfach, aber wissen Sie, wie Sie Ereignisse in rohem JavaScript verbinden? Heute werde ich dir genau das beibringen!


Willkommen bei JavaScript-Events

Der Umgang mit JavaScript-Ereignissen ist keine Hexerei. Natürlich gibt es Browserunterschiede (was haben Sie erwartet?), Aber wenn Sie erst einmal den Dreh raus haben und eigene Helferfunktionen für das Spielfeld aufbauen, werden Sie froh sein, dass Sie es wissen. Selbst wenn Sie immer noch vorhaben, eine Bibliothek für solche Dinge zu verwenden, ist es gut zu wissen, was unter der Oberfläche passiert. Auf geht's.


Level 0 Ereignisbehandlung

Die grundlegendste Ereignisbehandlung in JavaScript ist die Ereignisbehandlung der Stufe 0. Es ist ziemlich einfach: Weisen Sie einfach die Funktionseigenschaft des Elements zu. Beobachten:

 var element = document.getElementById ('myElement'); element.onclick = function () alert ('Ihre Funktion hier'); ;

Sobald ich das Element habe, setze ich das onclick Eigenschaft gleich einer Funktion. Jetzt, wenn Element Wenn Sie auf klicken, wird diese Funktion ausgeführt, und wir werden ein Benachrichtigungsfeld sehen.
Aber woher wusste ich es zu gebrauchen onclick? Eine Liste der verfügbaren Ereignisse finden Sie bei Wikipedia. Das Schöne an der Level 0-Methode ist, dass sie von allen heute verbreiteten Browsern unterstützt wird. Der Nachteil ist, dass Sie jedes Ereignis nur einmal mit jedem Element registrieren können. Dies führt also nur zu einer Warnung:

 element.onclick = function () alert ('funktion 1'); ; element.onclick = function () alert ('Ich überschreibe Funktion 1');

Es wird nur die zweite Funktion ausgeführt, wenn auf das Element geklickt wird, da die Eigenschaft onclick neu zugewiesen wurde. Um einen Event-Handler zu entfernen, können Sie ihn einfach auf null setzen.

 element.onclick = null;

Obwohl es nur grundlegende Funktionen bietet, macht die konsistente Unterstützung für alle Browser die Ereignisbehandlung der Stufe 0 zu einer gültigen Option für sehr einfache Projekte.


Full Screencast



Das Ereignisobjekt und das

Nachdem Sie sich nun mit JavaScript-Ereignissen beschäftigt haben, lassen Sie uns zwei wichtige Aspekte besprechen, bevor Sie mit besseren Techniken fortfahren: dem Ereignisobjekt und dem diese Stichwort. Wenn ein Ereignis ausgeführt wird, gibt es viele Informationen zu dem Ereignis, das Sie vielleicht wissen möchten: Welche Taste wurde gedrückt? Welches Element wurde angeklickt? Hat der Benutzer mit der linken, rechten oder mittleren Taste geklickt? Alle diese Daten und mehr werden in einem Ereignisobjekt gespeichert. Bei allen Browsern außer Internet Explorer können Sie zu diesem Objekt gelangen, indem Sie es als Parameter an die Handhabungsfunktion übergeben. Im IE können Sie es von der globalen Variablen erhalten window.event. Es ist nicht schwer, diesen Unterschied zu lösen.

 function myFunction (evt) evt = evt || window.event; / *… * / Element.onclick = meineFunktion;

meineFunktion übernimmt den Ereignisparameter für alle guten Browser und wir weisen ihn neu zu window.event ob evt existiert nicht Wir werden uns später einige Eigenschaften des Ereignisobjekts ansehen.

Das diese Schlüsselarbeit ist wichtig für Funktionen zur Ereignisbehandlung. es bezieht sich auf das Element, das das Ereignis erhalten hat.

 element.onclick = function () this.style.backgroundColor = 'red'; // dasselbe wie element.style.backgroundColor = 'red'; 

Leider im Internet Explorer, diese bezieht sich nicht auf das agierte Element; es bezieht sich auf das Fensterobjekt. Das ist sinnlos, aber wir werden einen Weg suchen, um dies in einiger Zeit zu verbessern.


Level 2 Event Handling

Die Behandlung von Ereignissen der Stufe 2 ist die W3C-Spezifikation für DOM-Ereignisse. Es ist eigentlich ganz einfach.

 element.addEventListener ('mouseover', myFunction, false);

Die Methode wird aufgerufen addEventListener. Der erste Parameter ist die Art des Ereignisses, auf das wir warten möchten. Normalerweise ist dies derselbe Name wie bei Ereignissen der Stufe 0, jedoch ohne das Präfix 'on'. Der zweite Parameter ist entweder ein Funktionsname oder die Funktion selbst. Der letzte Parameter bestimmt, ob wir erfassen oder nicht. Wir werden das gleich besprechen.
Einer der großen Vorteile der Verwendung addEventListener ist, dass wir jetzt mehrere Ereignisse für ein einzelnes Ereignis einem einzelnen Element zuordnen können:

 element.addEventListener ('dblclick', logSuccessToConsole, false); element.addEventListener ('dblclick', function () console.log ('Diese Funktion überschreibt nicht die erste.');, false);

Um diese Handler zu entfernen, verwenden Sie die Funktion removeEventListener. So entfernen Sie die oben hinzugefügte Funktion:

 element.removeEventListener ('dblclick', logSuccessToConsole, false);

Aufnehmen und Sprudeln

Der letzte Parameter in addEventListner und removeEventListener ist ein boolescher Wert, der festlegt, ob das Ereignis in der Erfassungsphase oder im Blubbern ausgelöst wird. Das heißt, was das bedeutet:
Wenn Sie auf ein Element klicken, klicken Sie auch auf jedes seiner Vorfahrenelemente.

  
Arbeit speichern

Wenn ich auf das klicke span # speichern, Ich habe auch geklickt div # Symbolleiste, div # wrapper, und Karosserie. Wenn also bei einem dieser Elemente Ereignis-Listener auf Klicks warten, werden deren jeweilige Funktionen aufgerufen. Aber in welcher Reihenfolge sollen sie gerufen werden? Das entscheidet der letzte Parameter. In der W3C-Spezifikation würde unser Klickereignis am beginnen Karosserie und die Kette nach unten bewegen, bis sie das erreicht span # speichern; Das ist die Eroberungsphase. Dann geht es aus dem span # speichern zurück zum Karosserie; das ist die sprudelnde Phase. Dies ist leicht zu merken, weil Blasen nach oben schweben. Nicht alle Ereignisse sprudeln. In dieser Wikipedia-Tabelle erfahren Sie, welche und welche nicht.

Wenn also der Capture-Parameter auf gesetzt ist wahr, Das Ereignis wird auf dem Weg nach unten ausgelöst. wenn es eingestellt ist falsch, es wird auf dem Weg nach oben ausgelöst.

Sie haben vielleicht bemerkt, dass bisher alle meine Beispiele die Erfassung auf "false" gesetzt haben, sodass das Ereignis in der Blubberstufe ausgelöst wird. Dies liegt daran, dass Internet Explorer keine Erfassungsphase hat. Im IE blubbern nur Ereignisse.


Internet Explorer-Ereignismodell

IE verfügt über eine eigene, proprietäre Art, mit Ereignissen zu arbeiten. Es verwendet attachEvent.

 element.attachEvent ('onclick', runThisFunction);

Da nur IE-Ereignisse blubbern, benötigen Sie die dritte Variable nicht. Die ersten beiden sind die gleichen wie bei addEventListener, mit der großen Ausnahme, dass der IE das Präfix 'on' für den Ereignistyp erfordert. Natürlich können Sie mit diesem Modell einem einzelnen Element mehrere Ereignisse einer Art zuordnen. Um Ereignisse zu entfernen, verwenden Sie detachEvent.

 element.detachEvent ('onclick', runThisFunction);

Momentan zurück zum Sprudeln

Was ist, wenn Ihre Elemente nicht möchten, dass ihre Eltern von ihren Ereignissen erfahren? Es ist nicht schwer sich zu verstecken. Im IE verwenden Sie die cancelBubble Eigenschaft für das Ereignisobjekt, das an die aufgerufene Funktion übergeben wird. Für den Rest können Sie die verwenden stopPropogation Methode, auch für das Ereignisobjekt.

 e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation (); 

Das stopPropogation Die Methode stoppt auch Ereignisse in ihren Spuren während der Erfassungsphase.


Einige Eigenschaften des Ereignisobjekts

Ich würde darauf wetten, dass die meisten Eigenschaften des Ereignisobjekts nicht verwendet werden. Es gibt jedoch einige ausgewählte, die für Sie von unschätzbarem Wert sind. Schauen wir uns diese wenigen an.


Ziel

Das Ziel Eigenschaft ist das tiefste Element, auf das geklickt wurde. Im Bild oben sehen Sie, dass ich geklickt habe h1 # -Taste. Im IE wird diese Eigenschaft aufgerufen srcElement; Um in diese Eigenschaft zu gelangen, tun Sie so etwas:

 var target = e.target || e.srcElement;

derzeitiges Ziel

Das derzeitiges Ziel Eigenschaft ist das Element, das das Ereignis jetzt hat. In diesem Screenshot die derzeitiges Ziel ist div # wrapper. Dies bedeutet, dass ich geklickt habe h1 # -Taste, Das Ereignisobjekt wurde jedoch in der von der aufgerufenen Funktion auf der Konsole protokolliert div # wrapperEreignis-Listener.

Aber das wird Sie für eine Schleife werfen: IE hat keine currentTarget -Eigenschaft oder ähnliches. Erinnert an die Tatsache, dass der IE nicht einmal lässt diese gleich dem Element, das das Ereignis auslöst, bedeutet dies, dass es nicht möglich ist, das Element zu erhalten, das das Ereignis ausgelöst hat, wenn das Ereignis sprudelt (dh ein Nachkomme des Elements wurde angeklickt). Verwirrt? Vielleicht hilft ein Beispiel: Wenn wir im Internet Explorer dieses HTML haben ...

 
Taste

… Und dieser Eventhandler…

 var par = document.getElementById ('parent'); parent.attachEvent ('onclick', doSomething);

… Dann, wenn wir auf klicken span # Kind und die Veranstaltung sprudelt bis div # parent, Wir haben keinen Weg aus der Funktion heraus etwas tun an das Element kommen (in diesem Fall, div # parent) das Ereignis wurde am ausgelöst.

Andere

Es gibt andere Eigenschaften für das Ereignisobjekt, die je nach Fall nützlich sind. Bei einem Tastaturereignis (keyup, keydown, keypress) werden Sie das keyCode und das charCode. Sie können feststellen, ob der Benutzer die Taste alt, shift oder ctrl (cmd) gedrückt hat, während Sie / klicken. Erkunden Sie die Ereignisobjekte verschiedener Ereignisse und sehen Sie, mit was Sie arbeiten müssen!


Ereignisse beheben

Bei der Untersuchung von Ereignissen sind wir bisher auf zwei Hauptprobleme gestoßen.

  • IE verwendet ein anderes Modell als die anderen Browser.
  • Der IE hat keine Möglichkeit, auf das übergeordnete Objekt des Ereignisses zuzugreifen. es fehlt das derzeitiges Ziel Eigentum und die diese Objekt verweist auf das Fensterobjekt.

Um diese Probleme zu lösen, erstellen wir zwei Funktionen mit Browserübergreifender Unterstützung, eine zum Verbinden von Ereignissen und eine zum Entfernen dieser.

Wir fangen mit an Ereignis hinzufügen; hier ist runde eins:

 var addEvent = Funktion (Element, Typ, Fn) if (Element.attachEvent) Element.attachEvent ('On' + Typ, Fn);  else element.addEventListener (type, fn, false); 

Ich weise der Variablen eine anonyme Funktion zu Ereignis hinzufügen aus Gründen, die Sie in einer Minute sehen werden. Alles, was wir tun müssen, ist zu prüfen, ob das Element das hat attachEvent Methode. Wenn dies der Fall ist, befinden wir uns im IE, und wir verwenden diese Methode. Wenn nicht, können wir verwenden addEventListener.

Dies behebt jedoch nicht die Tatsache, dass wir nicht auf das übergeordnete Element des Ereignisses im IE zugreifen können. Dazu machen wir die Funktion zu einem Attribut für das Element. auf diese Weise wird es als eine Methode des Elements wahrgenommen und diese wird gleich dem Element sein. Ja, ich weiß, brillant, nicht wahr? Nun, ich kann kein Verdienst annehmen: Diese Idee stammt von einem Blogbeitrag von John Resig.

 var addEvent = Funktion (Element, Typ, Fn) if (Element.attachEvent) Element ['e' + Typ + Fn] = Fn; Element [Typ + Fn] = Funktion () Element ['e' + Typ + Fn] (Fenster.Event); element.attachEvent ('on' + type, element [type + fn]);  else element.addEventListener (type, fn, false); 

Die erste zusätzliche Zeile (Element ['e' + Typ + Fn] = Fn;) macht die Funktion zu einer Methode des Elements, so dass diese wird jetzt gleich dem Element sein. Die zweite Zeile ist eine Funktion, die die Methode ausführt und an das window.event -Objekt übergeben wird. Dies erspart Ihnen den zusätzlichen Schritt der Überprüfung des Ereignisobjektparameters in Ihrer Funktion. Beachten Sie schließlich, dass wir den Funktionsparameter in geändert haben attachEvent Methode zu Element [Typ + Fn].

Das löst unsere beiden Probleme. Wir können jetzt unsere verwenden Ereignis hinzufügen Funktion in allen Browsern mit möglichst ähnlichen Erfahrungen. Aber es gibt eine kleine Optimierung, die wir gerne machen würden.

Beachten Sie, dass jedes Mal unser Ereignis hinzufügen Funktion aufgerufen wird, prüft sie nach attachEvent Methode. Es gibt keinen Grund, warum wir dies mehr als einmal überprüfen sollten, unabhängig davon, wie viele Ereignisse wir registrieren möchten. Wir können einen raffinierten Trick verwenden, mit dem wir neu schreiben können Ereignis hinzufügen.

 var addEvent = function (el, type, fn) if (el.attachEvent) addEvent = function (el, type, fn) el ['e' + type + fn] = fn; el [type + fn] = Funktion () el ['e' + type + fn] (window.event); ; el.attachEvent ('on' + type, el [type + fn]);  else addEvent = Funktion (el, type, fn) el.addEventListener (type, fn, false);  addEvent (el, type, fn); 

Nun, wenn die Ereignis hinzufügen Methode gefunden, schreiben wir neu Ereignis hinzufügen um nur die IE-Teile aufzunehmen; Wenn nicht, nehmen wir nur die guten Browser-Teile auf.
Unsere removeEvent Funktion wird sehr ähnlich sein:

 var removeEvent = Funktion (Element, Typ, Fn) if (Element.detachEvent) RemoveEvent = Funktion (Element, Typ, Fn) Element.detachEvent ('On' + Typ, El [Typ + Fn]); Element [Typ + Fn] = Null;  else removeEvent = Funktion (Element, Typ, Fn) Element.removeEventListener (Typ, Fn, False);  removeEvent (Element, Typ, Fn); 

Das war es für unsere Cross-Browser-Eventfunktionen. Es gibt jedoch eine Sache, die ich an ihnen nicht mag: Die Funktionen sind keine Methoden der Elemente; Stattdessen ist das Element ein Parameter. Ich weiß, es ist nur eine Frage des Stils, aber ich mag es

 btn.addEvent ('click', doThis);

besser als

 addEvent (btn, "click", doThis);

Wir könnten dies tun, indem wir unsere Funktionen so einwickeln:

 var E = Element.prototyp; E.addEvent = Funktion (Typ, Fn) AddEvent (Dies, Typ, Fn);  E.removeEvent = Funktion (Typ, Fn) removeEvent (Dies, Typ, Fn); 

Dies funktioniert in allen modernen Browsern sowie in IE8. IE7 und IE6 ersticken Element. Das hängt von Ihrem Publikum ab. nimm es oder lass es!


Event-Delegation

Da Sie sich mit JavaScript-Ereignissen auskennen, sollten Sie Ihr nächstes Projekt nicht mit Ereignis-Listenern füllen. Wenn viele Elemente auf den gleichen Ereignistyp reagieren (z. B. Klicken), ist es klüger, das Sprudeln zu nutzen. Sie können einem Vorfahrenelement, sogar dem Hauptteil, einfach einen Ereignis-Listener hinzufügen und die target / srcElement -Eigenschaft des Ereignisobjekts verwenden, um herauszufinden, auf welches tiefer liegende Element geklickt wurde. Dies wird als Ereignisdelegation bezeichnet. Hier ist ein nutzloses Beispiel:

Hier ist etwas HTML:

 
  • Zuhause
  • Portfolio
  • Über
  • Kontakt

Wir können die Ereignisdelegation verwenden, um Klicks für jeden zu bearbeiten li:

 Funktionsnavigation (e) var el = e.target || e.srcElement; switch (el.id) case 'home': alert ('go home'); brechen; Fall "Portfolio": Alarm ("Meine Produkte überprüfen"); brechen; Fall 'about': alert ('all die ekelhaften Details'); brechen; case 'contact': alert ('Ich bin geschmeichelt, dass Sie gerne reden'); brechen; default: alert ('wie bist du hier her gekommen?');  var nav = document.getElementById ('nav'); addEvent (nav, "click", navigation);

Wir verwenden eine switch / case-Anweisung, um die ID des tiefer geklickten Elements anzuzeigen. Dann machen wir etwas entsprechend.


Fazit

So können Sie jetzt JavaScript-Events mit den Besten davon durchführen. Viel Spaß damit und fragt in den Kommentaren nach!