-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathevent-handling-fortgeschritten.html
206 lines (182 loc) · 15.3 KB
/
event-handling-fortgeschritten.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>JavaScript: Fortgeschrittene Ereignis-Verarbeitung</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="js-doku.css">
</head>
<body>
<div id="nav">
<p>Hier entsteht eine <strong>JavaScript-Dokumentation</strong> von <a href="https://molily.de/">molily</a>. Derzeit ist sie noch lückenhaft, wächst aber nach und nach. Kommentare und Feedback werden gerne per <a href="mailto:[email protected]">E-Mail</a> entgegen genommen.</p>
<p class="contents-link"><a href="./">Zum Inhaltsverzeichnis</a></p>
</div>
<h1>JavaScript: Fortgeschrittene Ereignis-Verarbeitung</h1>
<div class="section" id="traditionell-nachteile">
<h2>Nachteile des traditionellen Event-Handlings</h2>
<p>Das <a href="event-handling-grundlagen.html#traditionelles-event-handling">traditionelle Event-Handling</a> basiert darauf, dass ein Funktionsobjekt in einer Eigenschaft des Elementobjekts gespeichert wird. Wir erinnern uns an das Schema:</p>
<pre>element.onevent = handlerfunktion;</pre>
<p>Der Vorteil dieses Schemas ist seine Einfachheit. Will man ein Ereignis überwachen, schreibt man bloß die Handler-Funktion in eine entsprechende Element-Eigenschaft. Der größte Nachteile ist jedoch folgender: Es kann nur <em>eine</em> Handler-Funktion zugleich registriert werden. Denn in der Eigenschaft kann nur eine Funktion gespeichert werden. Weist man eine andere Funktion zu, überschreibt man die erste.</p>
<p>In manchen Fällen mag <em>eine</em> Handler-Funktion für ein Element und Ereignistyp ausreichen. Diese kann schließlich weitere Funktionen aufrufen, sodass nicht der gesamte auszuführende Code direkt in dieser einen Funktion stehen muss. Doch wenn verschiedene Scripte zusammenarbeiten, besteht die Gefahr, dass sie beim traditionellen Event-Handling einander in die Quere kommen.</p>
<p>Wenden wir uns den fortgeschrittenen Modellen für Event-Handling zu, die es problemlos erlauben, mehrere Handler-Funktionen zu registrieren.</p>
</div>
<div class="section" id="dom-events">
<h2>Event-Handling gemäß dem DOM-Standard</h2>
<p>Das bisher beschriebene traditionelle Schema stammt aus den Anfangstagen von JavaScript. Der Browserhersteller und JavaScript-Erfinder Netscape erfand das Schema einst und andere Browser übernahmen es im Zuge ihrer JavaScript-Unterstützung.</p>
<p>Die Entwicklung ging jedoch weiter: Bei der Standardisierung des Event-Handlings verwarf das World-Wide-Web-Konsortium das traditionelle Event-Handling. Der DOM-Standard sieht ein anderes Modell vor: Alle Elementobjekte und weitere zentrale Objekte besitzen die Methode <code>addEventListener</code> (englisch für <em>Ereignis-Überwacher hinzufügen</em>). Will man dem Element einen Event-Handler zuweisen, so ruft man diese Methode auf.</p>
<div class="section" id="addEventListener">
<h3>Event-Handler registrieren: <code>addEventListener</code></h3>
<p>Das standardisierte Schema enthält ebenfalls die drei Bestandteile Elementobjekt, Ereignistyp und Handler-Funktion. Es lautet folgendermaßen:</p>
<pre>element.addEventListener('event', handlerfunktion, capturing);</pre>
<p>Die Methode erwartet also drei Parameter:</p>
<ol>
<li>Der erste Parameter ist ein String und enthält den <strong>Ereignistyp</strong>. Beispiele für den ersten Parameter sind <code>'click'</code>, <code>'mouseover'</code>, <code>'load'</code>, <code>'submit'</code> und so weiter.</li>
<li>Der zweite Parameter ist der Name der <strong>Handler-Funktion</strong>. Genauer gesagt ein <a href="syntax.html#ausdruecke">Ausdruck</a>, der ein Funktionsobjekt ergibt.</li>
<li>
<p>Der dritte Parameter bestimmt, für welche <strong>Event-Phase</strong> der Handler registriert werden soll. Es handelt sich um einen Boolean-Parameter, d.h. sie können <code>true</code> oder <code>false</code> notieren.</p>
<p><code>false</code> steht für die <a href="event-handling-objekt.html#bubbling">Bubbling-Phase</a>, <code>true</code> für die weniger wichtige <a href="event-handling-effizient.html#capturing">Capturing-Phase</a>. Die genaue Bedeutung des dritten Parameters wird später erklärt werden. Standardmäßig sollten Sie hier <code>false</code> notieren.</p>
</li>
</ol>
<p>Das folgende Beispiel kennen wir bereits vom traditionellen Event-Handling. Dieses Mal nutzen wir die standardisierte Methode <code>addEventListener</code>:</p>
<pre>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Beispiel für addEventListener</title>
</head>
<body>
<button id="interaktiv">
Dies ist ein Button ohne Bedeutung, aber mithilfe von JavaScript können wir ihn
interaktiv gestalten. Klicken Sie diesen Button einfach mal mit der Maus an!
</button>
<script>
function clickHandler() {
window.alert('Button wurde geklickt!');
}
document.getElementById('interaktiv').addEventListener('click', clickHandler, false);
</script>
</body>
</html>
</pre>
<p>Folgendes hat sich geändert: Aus der Zuweisung</p>
<pre>document.getElementById('interaktiv').<strong>onclick = clickHandler</strong>;</pre>
<p>ist der Aufruf von <code>addEventListener</code> geworden:</p>
<pre>document.getElementById('interaktiv').<strong>addEventListener('click', clickHandler, false)</strong>;</pre>
<p>Das obige Beispiel funktioniert in allen modernen Browsern, jedoch nicht im Internet Explorer vor der Version 9. Die unterstützen den DOM-Standard noch nicht und die Methode <code>addEventListener</code> ist ihnen unbekannt.</p>
<p>Der Internet Explorer unterstützt den DOM-Events-Standard erst ab Version 9. Älteren Internet-Explorer-Versionen ist die Methode <code>addEventListener</code> unbekannt. Sie unterstützen stattdessen ein <a href="#microsoft">proprietäres Modell</a>.</p>
<p>Der Hauptvorteil von <code>addEventListener</code> ist, dass Sie für ein Element <strong>mehrere Handler-Funktionen</strong> für denselben Ereignistyp registrieren können. Passen wir das obige Beispiel so an, dass beim <code>button</code>-Element zwei Handler statt einem registriert werden:</p>
<pre>
function meldung1() {
window.alert('Erste Handler-Funktion ausgeführt!');
}
function meldung2() {
window.alert('Zweite Handler-Funktion ausgeführt!');
}
var button = document.getElementById('interaktiv');
button.addEventListener('click', meldung1, false);
button.addEventListener('click', meldung2, false);
</pre>
<p>Es werden zunächst zwei Handler-Funktionen namens <code>meldung1</code> und <code>meldung2</code> definiert.</p>
<p>Um die Wiederholung von <code>document.getElementById('interaktiv')</code> zu vermeiden, suchen wir das Elementobjekt einmal heraus und speichern es in der Variablen <code>button</code>. Dann werden die die Funktionen <code>meldung1</code> und <code>meldung2</code> als <code>click</code>-Handler registriert. Wenn Sie auf den Button klicken, dann sollten nacheinander zwei Meldefenster erscheinen – und zwar in der Reihenfolge, in der die Handler mittels <code>addEventListener</code> registriert wurden.</p>
</div>
<div class="section" id="removeEventListener">
<h3>Event-Handler entfernen: removeEventListener</h3>
<p>Sie können einmal mit <code>addEventListener</code> registrierte Handler wieder <strong>entfernen</strong>. Dazu existiert die Schwestermethode <code>removeEventListener</code> (englisch für <em>Ereignis-Empfänger entfernen</em>). Die Methode erwartet dieselben Parameter, die <code>addEventListener</code> beim Registrieren bekommen hat: Einen String mit dem Ereignistyp, die zu löschende Handler-Funktion und schließlich einen Boolean-Wert für die Event-Phase.</p>
<p>Um beide im Beispiel definierten Handler für das <code>button</code>-Element, <code>meldung1</code> und <code>meldung2</code>, wieder zu entfernen, notieren wir:</p>
<pre>
button.removeEventListener('click', meldung1, false);
button.removeEventListener('click', meldung2, false);
</pre>
</div>
</div>
<div class="section" id="microsoft">
<h2>Event-Handling gemäß Microsoft für ältere Internet Explorer</h2>
<p>Bevor der DOM-Standard verabschiedet wurde, erfand Microsoft eine eigene Alternative zum traditionellen Event-Handling. Diese hat sich nicht durchgesetzt und wurde nur vom Internet Explorer umgesetzt. Seit der Version 9 unterstützt der Internet Explorer den DOM-Standard. Daher ist das Microsoft-Modell noch für ältere Internet-Explorer-Versionen interessant.</p>
<p>Das Microsoft-Modell teilt einige Fähigkeiten mit <code>addEventListener</code> und <code>removeEventListener</code>, funktioniert im Detail jedoch anders und bringt einige Eigenheiten mit sich.</p>
<div class="section" id="attachEvent">
<h3>Event-Handler registrieren: attachEvent</h3>
<p>Das Microsoft-Modell definiert die Methode <code>attachEvent</code> zum Registrieren von Event-Handlern. Elementobjekte sowie einige zentrale Objekte besitzen diese Methode. Das Schema lautet folgendermaßen:</p>
<pre>element.attachEvent('onevent', handlerfunktion);</pre>
<p>Die Methode erwartet zwei Parameter:</p>
<ol>
<li>Der erste Parameter ist ein String und enthält den <strong>Ereignistyp</strong> mit der Vorsilbe <code>on</code>. Beispiele für den ersten Parameter sind <code>'onclick'</code>, <code>'onmouseover'</code>, <code>'onload'</code>, <code>'onsubmit'</code> und so weiter.</li>
<li>Der zweite Parameter ist der Name der <strong>Handler-Funktion</strong>. Genauer gesagt ein <a href="syntax.html#ausdruecke">Ausdruck</a>, der ein Funktionsobjekt ergibt).</li>
</ol>
<p>Wir greifen das bekannte Beispiel auf und setzen es mit dem Microsoft-Modell um:</p>
<pre>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Beispiel für attachEvent</title>
</head>
<body>
<button id="interaktiv">
Dies ist ein Button ohne Bedeutung, aber mithilfe von JavaScript können wir ihn
interaktiv gestalten. Klicken Sie diesen Button einfach mal mit der Maus an!
</button>
<script>
function clickHandler() {
window.alert('Button wurde geklickt!');
}
document.getElementById('interaktiv').attachEvent('onclick', clickHandler);
</script>
</body>
</html>
</pre>
<p>Das Beispiel hat sich gegenüber dem DOM-Standardmodell nur geringfügig geändert. Anstelle von <code>document.getElementById('interaktiv').addEventListener(…)</code> wurde <code>document.getElementById('interaktiv').attachEvent(…)</code> notiert.</p>
<p>Der Ereignistyp im ersten Parameter enthält nun den Präfix <code>on</code>: Aus <code>'click'</code> wird <code>'onclick'</code>. Der dritte Parameter, der die Event-Phase angibt, fällt weg. Denn Microsofts Modell unterstützt nur das Registrieren in der <a href="event-handling-objekt.html#bubbling">Bubbling-Phase</a>.</p>
<p>Auch mit <code>attachEvent</code> können Sie verschiedene Handler für denselben Ereignistyp definieren. Das obige Beispiel wird entsprechend angepasst:</p>
<pre>
function meldung1() {
window.alert('Erste Handler-Funktion ausgeführt!');
}
function meldung2() {
window.alert('Zweite Handler-Funktion ausgeführt!');
}
var button = document.getElementById('interaktiv');
button.addEventListener('onclick', meldung1);
button.addEventListener('onclick', meldung2);
</pre>
<p>Das Beispiel enthält nichts neues, die Aufrufe von <code>addEventListener</code> wurden auf die besagte Weise durch <code>attachEvent</code> ausgetauscht.</p>
</div>
<div class="section" id="detachEvent">
<h3>Event-Handler entfernen: detachEvent</h3>
<p>Auch das Microsoft-Modell bietet eine Methode, um registrierte Handler wieder zu entfernen. Sie nennt sich <code>detachEvent</code> und erwartet dieselben Parameter wie sein Gegenstück <code>attachEvent</code>.</p>
<p>Um die besagten <code>click</code>-Handler <code>meldung1</code> und <code>meldung2</code> wieder zu entfernen, notieren wir:</p>
<pre>
button.detachEvent('onclick', meldung1);
button.detachEvent('onclick', meldung2);
</pre>
</div>
<div class="section" id="microsoft-eigenheiten">
<h3>Eigenheiten des Microsoft-Modell</h3>
<p>Das Microsoft-Modell bringt eine erfreuliche und eine unerfreuliche Besonderheit mit sich:</p>
<ul>
<li>Bei der Verwendung von <code>attachEvent</code> gestaltet sich der <a href="event-handling-objekt.html#event-objekt">Zugriff auf das Event-Objekt</a> einfacher, als wir es vom traditionellen Event-Handling gewöhnt sind. Dort war der Zugriff über <code>window.event</code> nötig. Bei der Benutzung von <code>attachEvent</code> wird das Event-Objekt der Handler-Funktion als Parameter übergeben, wie wir es aus anderen Browsern gewohnt sind und wie es auch beim im DOM-Standard vorgeschrieben ist.</li>
<li>Der <a href="event-handling-objekt.html#currenttarget-target">Zugriff auf das verarbeitende Element</a> ist nicht möglich. Beim traditionellen Event-Handling hatten wir <code>this</code> kennengelernt, um das Element anzusprechen, bei dem die gerade ausgeführte Handler-Funktion registriert wurde. Das ist im Zusammenhang mit <code>attachEvent</code> nicht möglich, denn <code>this</code> zeigt nicht auf das gewünschte Objekt, sondern stets auf das globale Objekt <code>window</code> – und ist damit unbrauchbar.</li>
<li>Im Gegensatz zum DOM-Standard kennt das Microsoft-Modell keine <a href="event-handling-effizient.html#capturing">Capturing-Phase</a>.</li>
</ul>
</div>
</div>
<div class="section" id="addevent">
<h2>Browserübergreifendes Event-Handling</h2>
<p>Wir haben drei Modelle und deren Detailunterschiede kennengelernt. Sie werden sich sicher fragen, welches Sie nun in der Praxis ohne Bedenken anwenden können.</p>
<p>Mittlerweile unterstützen alle relevanten Browser den DOM-Standard. Das heißt, Sie können problemlos <code>addEventListener</code> und <code>removeEventListener</code> sowie <code>event.target</code> und <code>event.currentTarget</code> (siehe <a href="event-handling-objekt.html">Arbeiten mit dem Event-Objekt</a>) verwenden.</p>
<p>Der Internet Explorer vor Version 9 unterstützt den DOM-Standard nicht. Diese Versionen sind allerdings nicht mehr stark verbreitet. Falls Sie diese Versionen dennoch unterstützen müssen, so sollten Sie eine <a href="bibliotheken.html">Bibliothek</a> verwenden, die das browserübergreifende Registrieren von Event-Handlern ermöglicht. Ein Beispiel ist <a href="https://jquery.com/">jQuery 1.x</a>.</p>
</div>
<div class="sequence-navigation">
<p class="next"><a href="event-handling-onload.html" rel="next">Scripte beim Laden des Dokuments ausführen</a></p>
<p class="prev"><a href="event-handling-objekt.html" rel="prev">Arbeiten mit dem Event-Objekt</a></p>
</div>
<div id="footer">
<p><strong>JavaScript-Dokumentation</strong> · <a href="./">Zum Inhaltsverzeichnis</a></p>
<p>Autor: <a href="https://molily.de/">molily</a> · Kontakt: <a href="mailto:[email protected]">[email protected]</a></p>
<p>Lizenz: <a rel="license" href="https://creativecommons.org/licenses/by-sa/3.0/de/">Creative Commons Namensnennung - Weitergabe unter gleichen Bedingungen 3.0</a></p>
<p><a href="https://github.com/molily/javascript-einfuehrung">JavaScript-Einführung auf Github</a></p>
<p>Kostenloses Online-Buch und E-Book:<br><a href="https://testing-angular.com" lang="en" hreflang="en">Testing Angular – A Guide to Robust Angular Applications</a> (englisch)</p>
</div>
<script src="js-doku.js"></script>
</body>
</html>