EventTarget#
EventTarget.addEventListener()#
Metoda addEventListener()
rejestruje uchwyt zdarzenia (tzw. uchwyt przez metodę) dla danego celu zdarzenia. Za pomocą trzech argumentów przekazywanych do metody można skonkretyzować główne właściwości dodawanego uchwytu.
Składnia#
Samo wywołanie i poszczególne jego części najlepiej objaśnić na zapisie składniowym:
eventTarget.addEventListener(type, callback [, capture = false]);
gdzie poszczególne człony oznaczają:
eventTarget
- cel zdarzenia będący obiektem kontekstu.type
- typ zdarzenia w postaci łańcucha znakowego, które będzie nasłuchiwane. Może to być dowolny łańcuch znakowy (nawet pusty).callback
- funkcja zwrotna wywoływana w chwili obsługi zdarzenia.capture
- boolowskietrue
oznacza, że zdarzenie może zostać obsłużone w fazie przechwytywania i fazie celu. Boolowskiefalse
zezwala na obsługę zdarzenia w fazie bąbelkowania i fazie celu (domyślnie).
Algorytm wywołania metody addEventListener(type, callback, capture)
nie jest skomplikowany. Dla lepszego zrozumienia tematu prezentuję go w całości:
- Jeśli
callback
ma wartośćnull
, to pomiń kolejne kroki. - Dodaj uchwyt zdarzenia do powiązanej listy uchwytów zdarzeń dla obiektu kontekstu, z typem ustawianym na
type
, funkcją zwrotną ustawianą nacallback
oraz przechwytywaniem ustawianym nacapture
, ale tylko wtedy, kiedy nie istnieje już uchwyt zdarzenia na tej liście z takim samym typem, funkcją zwrotną i przechwytywaniem.
Warto podkreślić, że nasłuchy zdarzeń są unikatowe i nie mogą się powtarzać dla tego samego celu zdarzenia. Duplikaty są automatycznie usuwane przez implementację. Identyczność między nasłuchami zdarzeń jest określana na podstawie trzech argumentów przekazanych do metody addEventListener()
. Wystarczy, że tylko jeden z nich będzie inny, a będziemy mieli do czynienia z różnymi uchwytami zdarzeń.
Kiedy zdarzenie osiągnie swój element docelowy, to nasłuchy zdarzeń dla obydwu faz przechwytywania i bąbelkowania są wyzwalane w ramach fazy celu (właściwość Event.eventPhase
ma wartość 2
). Pod względem kolejności wykonania obydwa sposoby rejestracji będą równoważne dla tego przypadku, czyli decydujące znaczenie ma kolejność rejestracji wykonana przez programistę (szczegóły).
Kiedy kolejny nasłuch zdarzenia zostanie dodany do aktualnego celu zdarzania w trakcie przetwarzania innego nasłuchu zdarzenia, to nie będzie to miało wpływu na bieżące operacje, ale będzie respektowane w późniejszej fazie przepływu zdarzeń, np. w fazie bąbelkowania dla tego samego aktualnego celu zdarzenia, w dowolnej fazie dla innych aktualnych celów zdarzenia, lub w trakcie ponownego wysłania zdarzenia. Takie zamrożenie przed przetworzeniem kandydujących nasłuchów zdarzeń w aktualnym celu zdarzenia (dla danej fazy) gwarantuje, że przez przypadek nie doprowadzimy do błędnych zachowań lub zapętleń (np. dodając kolejne uchwyty).
Zamiast zawiłych regułek najlepiej przeanalizować jeden przykład teoretyczny. Załóżmy, że mamy do czynienia z następującą ścieżką propagacji jakiegoś zdarzenia:
faza przechwytywania faza celu faza bąbelkowania
W1 > W2 > W3 > W > W3 > W2 > W1
P1 P2 P3 P4 P5 B1 B2 B3 B4 B5
gdzie:
Wx
- węzły, które występują na ścieżce propagacji zdarzenia. Zdarzenie utworzone i wysłane zostaje dla węzłaW
.Px
- uchwyty zdarzeń rejestrowane (ewentualnie w późniejszym czasie) dla poszczególnych węzłów z obsługą w trakcie fazy przechwytywania/celu.Bx
- uchwyty zdarzeń rejestrowane (ewentualnie w późniejszym czasie) dla poszczególnych węzłów z obsługą w trakcie fazy celu/bąbelkowania.
Oto kilka przykładowych akcji wykonywanych z następujących uchwytów:
P1
rejestrujeP3
- nowy uchwytP3
zostanie wykonany dopiero przy ponownym wysłaniu zdarzenia.P1
rejestrujeP4
- nowy uchwytP4
zostanie wykonany w aktualnym wysłaniu zdarzenia.P5
rejestrujeB2
- nowy uchwytB2
zostanie wykonany dopiero przy ponownym wysłaniu zdarzenia.B3
rejestrujeB5
- nowy uchwytB5
zostanie wykonany w aktualnym wysłaniu zdarzenia.
Prosty przykład:
<!DOCTYPE html>
<html>
<head>
<script>
// Uruchom po całkowitym załadowaniu dokumentu
window.onload = function(){
var button = document.getElementById("press");
var info = document.getElementById("info");
var test = function(){
info.innerHTML += "Trzeci uchwyt dla przycisku." + "<br><br>";
};
// Uchwyt z anonimową funkcją zwrotną
button.addEventListener("click", function(e){
info.innerHTML += "Pierwszy uchwyt dla przycisku." + "<br><br>";
// Nie wykona się w aktualnej ścieżce propagacji zdarzenia (dla tego samego celu)
// Dopiero dla ponownego kliknięcia na przycisku uchwyt ten zostanie obsłużony
button.addEventListener("click", function(e){
info.innerHTML += "Uchwyt dla przycisku dodany z wnętrza pierwszego uchwytu." + "<br><br>";
}, false);
// Wykona się w tej fazie zdarzenia (ale dla innego późniejszego celu)
window.addEventListener("click", function(e){
info.innerHTML += "Uchwyt dla obiektu window dodany z wnętrza pierwszego uchwytu." + "<br><br>";
}, false);
}, true);
// Uchwyt z anonimową funkcją zwrotną
button.addEventListener("click", function(e){
info.innerHTML += "Drugi uchwyt dla przycisku." + "<br><br>";
}, false);
// Uchwyty z referencją do funkcji zwrotnej
button.addEventListener("click", test);
button.addEventListener("click", test, false); // Duplikat - w ogóle nie zostanie zarejestrowany
}
</script>
</head>
<body>
<p>Kliknij w przycisk by wywołać procedury obsługi wielu uchwytów zdarzeń.</p>
<input id="press" type="button" value="Kliknij mnie!">
<p style="color: blue;">Szczegółowe informacje:</p>
<p id="info"></p>
</body>
</html>
Interfejs Web IDL#
void addEventListener(DOMString type, EventListener? callback, optional boolean capture = false);