Event listenery w JavaScript: click, submit, scroll i delegacja
Event listenery w JavaScript
Event listenery w JavaScript: click, submit, scroll | We.Inc
Zobacz, jak zdarzenia pojawiają się w logu na żywo, a potem skopiuj wzorce addEventListener dla click, submit, scroll, delegacji, once, passive i sprzątania przez AbortController.
Event listener to funkcja, którą przeglądarka wywołuje, gdy coś dzieje się z elementem, na przykład kliknięcie, wysłanie formularza lub przewijanie. Dodajesz go przez element.addEventListener(type, handler, options). Obiekt options włącza once, passive, capture lub sygnał przerwania, a removeEventListener później odłącza tę samą funkcję.
Opcje addEventListener
Opcja
Domyślnie
Efekt
Automatycznie usuwa listener po pierwszym wywołaniu
false (true dla wheel i touch na window, document i body)
Obiecuje, że nie wywoła preventDefault, więc przewijanie nigdy nie czeka
Uruchamia się w drodze w dół do celu, a nie w drodze powrotnej w górę
AbortSignal: przerwanie go usuwa listener
Zdarzenia łatwiej zrozumieć, gdy je widać. Poniższy log zdarzeń zapisuje każde wywołanie listenera w małym obszarze testowym, więc możesz klikać, pisać, wysyłać i przewijać, obserwując kolejność, cel i efekt każdej opcji. Potem skopiuj wzorce do zadań, które naprawdę masz.
Użyj kontrolek w obszarze testowym: klikaj przyciski, pisz w polu, wyślij formularz i przewijaj pole.
Każde wywołanie listenera pojawia się w logu z typem zdarzenia, elementem, który je zapoczątkował, i elementem, który je obsłużył.
Włącz once, aby zobaczyć, jak listener znika po jednym wywołaniu, albo wyłącz delegację, aby lista obsługiwała kliknięcia osobno dla każdego elementu.
Skopiuj dowolny przykład poniżej. Każdy to czysty JavaScript bez biblioteki.
Przekazuj nazwaną funkcję, jeśli planujesz usunąć listener. Funkcji strzałkowej wpisanej w miejscu nie da się później dopasować.
AbortController usuwa całą grupę listenerów jednym wywołaniem abort(), co pasuje do komponentów, które są montowane i odmontowywane.
Nasłuchuj submit na formularzu, a nie click na przycisku, aby obsłużyć też naciśnięcie Enter w polu.
W delegowanych handlerach używaj event.target.closest("selector"). Kliknięcie ikony wewnątrz przycisku i tak znajdzie przycisk.
focus i blur nie bąbelkują. Zamiast nich deleguj focusin i focusout.
Najczęściej zadawane pytania
Czym jest delegacja zdarzeń?
Zamiast dodawać listener do każdego elementu, dodajesz jeden do wspólnego rodzica. Ponieważ większość zdarzeń bąbelkuje w górę, rodzic słyszy kliknięcia wszystkich swoich dzieci, także tych dodanych później, i używa event.target, by ustalić, które zostało kliknięte.
Dlaczego removeEventListener nie usuwa mojego listenera?
Musi dostać tę samą referencję do funkcji i to samo ustawienie capture, które dostał addEventListener. Dwie funkcje strzałkowe o identycznym kodzie to nadal różne funkcje, więc zdefiniuj handler raz i przekaż tę zmienną za każdym razem.
Co robi passive: true?
Informuje przeglądarkę, że Twój handler nie wywoła preventDefault, więc strona może zacząć przewijać się od razu, zamiast czekać na zakończenie Twojego kodu. Przeglądarki domyślnie ustawiają passive dla listenerów wheel i touch na window, document i body.
Czym różni się target od currentTarget?
target to najgłębiej położony element, w którym zdarzenie się zaczęło, i pozostaje taki sam podczas bąbelkowania. currentTarget to element, którego listener działa w tej chwili, i zmienia się na każdym poziomie.
Czy form.submit() wywołuje zdarzenie submit?
Nie. Wywołanie form.submit() ze skryptu pomija zdarzenie submit i walidację. Wywołaj form.requestSubmit(), gdy chcesz, aby uruchomiły się Twoje listenery submit i wbudowane sprawdzenia.
addEventListener czy onclick?
Właściwość onclick przechowuje jedną funkcję, więc przypisanie drugiej zastępuje pierwszą. addEventListener pozwala kilku niezależnym listenerom dzielić element i obsługuje obiekt options, więc to lepszy domyślny wybór.
Jak podróżuje zdarzenie
Wysłane zdarzenie przechodzi przez trzy fazy. W fazie capture schodzi od window do celu, dociera do celu, a potem bąbelkuje z powrotem w górę przez każdego przodka. Listenery działają w fazie bąbelkowania, chyba że poprosisz o capture.
stopPropagation zatrzymuje tę podróż, więc przodkowie nigdy go nie usłyszą. Używaj go rzadko, bo delegowane listenery i analityka wyżej w drzewie po cichu przestają działać.
Przewijanie bez spowalniania strony
Zdarzenia scroll mogą wystąpić wiele razy na klatkę ruchu. Utrzymuj handler maleńki, odczytuj pozycje zamiast zmieniać layout i grupuj zmiany wizualne w requestAnimationFrame.
Do zadań takich jak pokazywanie elementów, gdy wchodzą w widok, IntersectionObserver jest zwykle tańszy niż mierzenie przy każdym przewinięciu. Zdarzenie scrollend, według MDN w Baseline od grudnia 2025, uruchamia się raz, gdy ruch się zatrzyma.
Sprzątanie listenerów
Listenery na długo żyjących obiektach, takich jak window czy document, utrzymują w pamięci swój handler i wszystko, do czego się odwołuje. Gdy część strony, która ich potrzebowała, znika, usuń je.
Opcja signal porządkuje to. Utwórz jeden AbortController na funkcję, przekaż jego signal każdemu listenerowi i wywołaj abort() raz podczas sprzątania.
Typy zdarzeń, których użyjesz najczęściej
Popularne zdarzenia i gdzie ich nasłuchiwać
Zdarzenie
Kiedy występuje
Bąbelkuje?
Naciśnięcie i zwolnienie wskaźnika albo Enter lub Space na przycisku
Tak
Wartość pola zmienia się, gdy odwiedzający pisze
Tak
Wartość pola zostaje zatwierdzona, na przykład przy blur lub wyborze
Tak
Formularz zostaje wysłany: występuje na elemencie form
Tak
Naciśnięto klawisz
Tak
focus / blur
Element zyskuje lub traci fokus
Nie
focusin / focusout
To samo co focus i blur, ale z bąbelkowaniem
Tak
DOMContentLoaded
HTML został sparsowany, a odroczone skrypty wykonane: nasłuchuj na document
Nie dotyczy
Wzorce do skopiowania
Kliknięcie z nazwanym handlerem, który można usunąć
Trzymanie funkcji w zmiennej sprawia, że removeEventListener działa.
Obsługa wysłania formularza bez przeładowania
preventDefault zatrzymuje nawigację przeglądarki. event.submitter mówi, którego przycisku wysyłania użyto.
Delegacja zdarzeń na liście
Jeden listener na liście obsługuje każdy przycisk usuwania, także wiersze dodane po załadowaniu strony.
Pasywny listener scroll ograniczony do jednej aktualizacji na klatkę
passive: true pozwala przewijaniu zacząć się od razu, a requestAnimationFrame ogranicza pracę do raz na klatkę.
once i AbortController
Pierwszy listener działa jeden raz. Pozostałe są usuwane razem jednym wywołaniem abort().
Skrót klawiszowy, który ignoruje pisanie w polach
Sprawdzenie celu sprawia, że skrót nie zadziała, gdy ktoś wpisuje ukośnik w polu wyszukiwania.
Jabłka
Chleb
Kawa
click na przycisku: target {target}
(once: teraz usunięty)
click dotarł do obszaru testowego (faza {phase}): target {target}, currentTarget {current}
input: wartość to teraz "{value}"
change: wartość zatwierdzona
submit na formularzu, submitter {submitter}; preventDefault zatrzymał przeładowanie
scroll (pasywny, raz na klatkę): scrollTop {n}
delegowany click na liście: element {item}
listener na elemencie: {item}
Log zdarzeń na żywo
Klikaj, pisz, wysyłaj i przewijaj w obszarze testowym. Każde wywołanie listenera trafia do logu z typem, celem i bieżącym celem.