Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Custom Events i dispatchEvent w JavaScript

"Posłuchaj uważnie," mówi Dr. Alan Grant, pochylając się nad konsolą systemu monitoringu. "Dinozaury komunikują się ze sobą za pomocą dźwięków - od niskich pomruków po przerażliwe ryki. W naszym parku potrzebujemy podobnego systemu komunikacji między modułami. I tu właśnie wkraczają Custom Events!"

Czym są Custom Events?

Do tej pory poznaliśmy wbudowane zdarzenia DOM -

click
,
keydown
,
submit
czy
scroll
. Ale JavaScript pozwala nam tworzyć własne, niestandardowe zdarzenia. Dzięki nim możemy budować systemy komunikacji między różnymi częściami aplikacji, podobnie jak system alarmowy w Parku Jurajskim wysyła powiadomienia do różnych stref.

Custom Events to zdarzenia definiowane przez programistę, które mogą przenosić dowolne dane i być nasłuchiwane tak samo jak zwykłe zdarzenia DOM.

Konstruktor CustomEvent

Aby stworzyć własne zdarzenie, używamy konstruktora

CustomEvent
:

1// Podstawowe tworzenie Custom Event
2const alertEvent = new CustomEvent('dinoAlert');
3
4// Custom Event z dodatkowymi danymi (detail)
5const escapeEvent = new CustomEvent('dinoEscape', {
6  detail: {
7    dinosaur: 'Velociraptor',
8    zone: 'B',
9    severity: 'critical'
10  }
11});
12
13// Dostęp do danych zdarzenia
14console.log(escapeEvent.detail.dinosaur); // "Velociraptor"
15console.log(escapeEvent.detail.severity); // "critical"
16console.log(escapeEvent.type);            // "dinoEscape"

Obiekt

detail
to specjalne pole Custom Events, w którym możemy przekazać dowolne dane. Jest to jedyny sposób na dołączenie informacji do niestandardowego zdarzenia.

Opcje CustomEvent

Konstruktor

CustomEvent
przyjmuje drugi argument - obiekt opcji:

1const event = new CustomEvent('systemUpdate', {
2  detail: { module: 'security', status: 'active' },  // Dane zdarzenia
3  bubbles: true,     // Czy zdarzenie propaguje w górę DOM
4  cancelable: true,  // Czy można wywołać preventDefault()
5  composed: false    // Czy przechodzi przez Shadow DOM
6});
  • detail
    - obiekt z danymi, które chcemy przekazać
  • bubbles
    - domyślnie
    false
    ; ustaw na
    true
    , jeśli zdarzenie ma propagować w górę drzewa DOM (bubbling)
  • cancelable
    - domyślnie
    false
    ; ustaw na
    true
    , jeśli chcesz móc anulować zdarzenie przez
    preventDefault()

Wysyłanie zdarzeń - dispatchEvent

Sam obiekt zdarzenia nic nie robi - musimy go wysłać (dispatch) na konkretnym elemencie DOM:

1// Tworzymy element, który będzie emitował zdarzenia
2const controlPanel = document.getElementById('controlPanel');
3
4// Tworzymy zdarzenie
5const fenceAlert = new CustomEvent('fenceBreak', {
6  detail: {
7    zone: 'A',
8    voltage: 0,
9    dinosaur: 'T-Rex'
10  },
11  bubbles: true
12});
13
14// Wysyłamy zdarzenie na elemencie
15controlPanel.dispatchEvent(fenceAlert);

Metoda

dispatchEvent()
jest dostępna na każdym elemencie DOM. Po jej wywołaniu, zdarzenie zostaje natychmiast wysłane i wszystkie nasłuchujące handlery są wykonywane synchronicznie.

Nasłuchiwanie Custom Events

Custom Events nasłuchujemy dokładnie tak samo jak zwykłe zdarzenia - przez

addEventListener
:

1const controlPanel = document.getElementById('controlPanel');
2
3// Rejestrujemy listener dla naszego zdarzenia
4controlPanel.addEventListener('fenceBreak', function(event) {
5  const { zone, voltage, dinosaur } = event.detail;
6  console.log('ALARM! Ogrodzenie strefy ' + zone + ' uszkodzone!');
7  console.log('Dinozaur: ' + dinosaur);
8  console.log('Napięcie: ' + voltage + 'V');
9});
10
11// Inny moduł też może nasłuchiwać tego samego zdarzenia
12controlPanel.addEventListener('fenceBreak', function(event) {
13  if (event.detail.dinosaur === 'T-Rex') {
14    console.log('EWAKUACJA NATYCHMIAST!');
15  }
16});
17
18// Wysyłamy zdarzenie - oba listenery zostaną wywołane
19controlPanel.dispatchEvent(new CustomEvent('fenceBreak', {
20  detail: { zone: 'A', voltage: 0, dinosaur: 'T-Rex' }
21}));

Praktyczny przykład: System alarmowy parku

Zobaczmy kompletny przykład systemu komunikacji między modułami:

1// System monitoringu Parku Jurajskiego
2const parkSystem = document.getElementById('parkSystem');
3
4// Moduł bezpieczeństwa nasłuchuje alarmów
5parkSystem.addEventListener('securityAlert', function(event) {
6  const { type, zone, message } = event.detail;
7  const alertDiv = document.createElement('div');
8  alertDiv.className = 'alert alert-' + type;
9  alertDiv.textContent = '[' + zone + '] ' + message;
10  document.getElementById('alerts').appendChild(alertDiv);
11});
12
13// Moduł monitoringu dinozaurów nasłuchuje statusów
14parkSystem.addEventListener('dinoStatus', function(event) {
15  const { name, heartRate, location } = event.detail;
16  console.log(name + ': HR=' + heartRate + ', lokacja=' + location);
17});
18
19// Funkcja emitująca alert bezpieczeństwa
20function emitSecurityAlert(type, zone, message) {
21  parkSystem.dispatchEvent(new CustomEvent('securityAlert', {
22    detail: { type, zone, message },
23    bubbles: true
24  }));
25}
26
27// Funkcja emitująca status dinozaura
28function emitDinoStatus(name, heartRate, location) {
29  parkSystem.dispatchEvent(new CustomEvent('dinoStatus', {
30    detail: { name, heartRate, location },
31    bubbles: true
32  }));
33}
34
35// Użycie
36emitSecurityAlert('warning', 'Zone B', 'Raptor aktywność podwyższona');
37emitSecurityAlert('critical', 'Zone A', 'Ogrodzenie uszkodzone!');
38emitDinoStatus('T-Rex', 85, 'Wybieg główny');

Bubbling w Custom Events

Domyślnie Custom Events nie propagują w górę drzewa DOM. Aby włączyć bubbling, musisz ustawić

bubbles: true
:

1// BEZ bubbles (domyślnie) - listener na rodzicu NIE złapie zdarzenia
2const child = document.getElementById('zoneA');
3const parent = document.getElementById('parkSystem');
4
5child.dispatchEvent(new CustomEvent('alert', {
6  detail: { msg: 'test' }
7  // bubbles domyślnie false
8}));
9
10parent.addEventListener('alert', (e) => {
11  // Ten handler NIE zostanie wywołany!
12  console.log('Parent caught:', e.detail);
13});
14
15// Z bubbles: true - zdarzenie propaguje do rodzica
16child.dispatchEvent(new CustomEvent('alert', {
17  detail: { msg: 'test' },
18  bubbles: true  // Teraz zdarzenie będzie propagować!
19}));
20
21parent.addEventListener('alert', (e) => {
22  // Ten handler ZOSTANIE wywołany!
23  console.log('Parent caught:', e.detail.msg); // "test"
24});

To jest szczególnie przydatne, gdy chcemy nasłuchiwać zdarzeń z wielu dzieci na jednym rodzicu (event delegation dla Custom Events).

Anulowanie Custom Events

Jeśli ustawisz

cancelable: true
, możesz anulować zdarzenie:

1const event = new CustomEvent('transferDino', {
2  detail: { dinosaur: 'T-Rex', from: 'A', to: 'B' },
3  cancelable: true,
4  bubbles: true
5});
6
7// Listener może anulować zdarzenie
8parkSystem.addEventListener('transferDino', function(e) {
9  if (e.detail.dinosaur === 'T-Rex') {
10    e.preventDefault(); // Anuluj transfer T-Rexa!
11    console.log('Transfer T-Rexa zablokowany ze względów bezpieczeństwa!');
12  }
13});
14
15// Sprawdzamy, czy zdarzenie zostało anulowane
16const wasNotCancelled = parkSystem.dispatchEvent(event);
17console.log('Transfer dozwolony:', wasNotCancelled); // false (bo preventDefault)

Metoda

dispatchEvent()
zwraca
false
, jeśli zdarzenie zostało anulowane przez
preventDefault()
. Dzięki temu emitujący może sprawdzić, czy akcja powinna być kontynuowana.

Przypadki użycia Custom Events

Custom Events świetnie sprawdzają się w wielu scenariuszach:

  1. Komunikacja między komponentami - gdy dwa niezależne moduły muszą wymieniać informacje
  2. System powiadomień - centralny hub, na którym różne moduły emitują zdarzenia
  3. Decoupling kodu - moduł emitujący nie musi wiedzieć, kto nasłuchuje
  4. Plugin system - zewnętrzne moduły mogą reagować na zdarzenia aplikacji
  5. Śledzenie akcji użytkownika - emitowanie zdarzeń analitycznych
1// Przykład: decoupling z Custom Events
2// Moduł koszyka nie wie nic o module powiadomień
3const cart = [];
4
5function addToCart(product) {
6  cart.push(product);
7
8  // Emituje zdarzenie - ktokolwiek chce, może nasłuchiwać
9  document.dispatchEvent(new CustomEvent('cartUpdated', {
10    detail: { product, totalItems: cart.length },
11    bubbles: true
12  }));
13}
14
15// Moduł powiadomień nasłuchuje niezależnie
16document.addEventListener('cartUpdated', (e) => {
17  console.log('Dodano: ' + e.detail.product.name);
18});
19
20// Moduł badge'a koszyka też nasłuchuje niezależnie
21document.addEventListener('cartUpdated', (e) => {
22  console.log('Koszyk: ' + e.detail.totalItems + ' elementów');
23});

Podsumowanie

Custom Events to potężne narzędzie do budowania luźno powiązanych (loosely coupled) systemów w JavaScript:

  • new CustomEvent(name, options)
    - tworzy niestandardowe zdarzenie
  • element.dispatchEvent(event)
    - wysyła zdarzenie na elemencie
  • detail
    - obiekt z danymi przekazywanymi w zdarzeniu
  • bubbles: true
    - włącza propagację zdarzenia w górę DOM
  • cancelable: true
    - pozwala anulować zdarzenie przez
    preventDefault()
  • Custom Events nasłuchujemy tak samo jak zwykłe zdarzenia DOM - przez
    addEventListener

"W Parku Jurajskim," podsumowuje Dr. Grant, "każdy system musi komunikować się z innymi. Custom Events to nasz wewnętrzny system radiowy - każdy moduł może nadawać i każdy może odbierać. Bez tego cały park pogrążyłby się w chaosie."

Ir a CodeWorlds