Zajęcia 7
12. Zdarzenia
12.1. Typy zdarzeń
Na tych zajęciach omówimy nastepujące typy zdarzeń:
- zdarzenia UI - występują, gdy użytkownik prowadzi interakcje z graficznym interfejsem użytkownika (ang. user interface - UI) przeglądarki, a nie ze samą stroną;
- zdarzenia klawiatury - występują, gdy użytkownik prowadzi interakcje z klawiaturą;
- zdarzenia myszy - występują, gdy użytkownik prowadzi interakcje z myszą lub ekranem dotykowym;
- zdarzenia aktywności - występują, gdy dany element (np. łącze) staje się aktywny bądź nieaktywny;
- zdarzenia dotyczące zmian - występują, gdy nastąpi zmiana struktury modelu DOM na skutek działania skryptu.
Terminologia:
- o zdarzeniu możemy powiedzieć, że zostało zgłoszone lub wywołane;
- mówi się, że zdarzenia wywołują funkcję lub skrypt.
12.2. Wywoływanie kodu JavaScript przez zdarzenia
Kiedy użytkownik prowadzi interakcje z kodem HTML na stronie internetowej, mamy trzy kroki prowadzące do wywołania pewnego kodu JavaScript. Razem te kroki są określane mianem procedury obsługi zdarzeń:
- wybór elementu - wybieramy węzeł elementu, do którego skrypt ma przesłać odpowiedź;
- wskazanie zdarzenia - wskazujemy zdarzenie, które w wybranym elemencie spowoduje udzielenie odpowiedzi;
- wywołanie kodu - definiujemy kod uruchamiany po wystąpieniu zdarzenia.
12.3. Dołączenie zdarzenia do elementu
Tradydycjna procedura obsługi zdarzeń w modelu DOM
Przykład 12.1.
function myFunction() {
// treść funkcji
}
var el = document.getElementById('id-elementu');
el.onclick = myFunction;
Obserwatory zdarzeń
Obserwatory zdarzeń to najnowsze podejście w zakresie procedur obsługi zdarzeń. Dzięki nim można przypisać zdarzeniu wiele funkcji, ale jednocześnie obserwatory zdarzeń nie są obsługiwane w starszych wersjach przeglądarek internetowych.
Przykład 12.2.
function myFunction() {
// treść funkcji
}
var el = document.getElementById('id-elementu');
el.addEventListener('click', myFunction, false);
Ćwiczenie 12.1.
Jak myślisz, dlaczego nie można używać nawiasów po nazwie funkcji, kiedy do elementu dołączamy jakieś zdarzenie?
Jak używać parametrów w procedurach obsługi zdarzeń i obserwatorach zdarzeń?
Ponieważ w procedurze obsługi zdarzeń oraz w obserwatorach zdarzeń nie można używać nawiasu po nazwie funkcji, możliwość przekazania argumentów funkcji wymaga zastosowania pewnej sztuczki.
Zwykle kiedy funkcja wymaga pewnych informacji, aby mogła wykonać swoje zadanie, odpowiednie argumenty są podawane w nawiasie znajdującym się po nazwie funkcji. Kiedy interpreter napotka nawias po nazwie funkcji natychmiast wykonuje jej kod. Jednak w przypadku procedury obsługi zdarzeń wykonanie kodu chcemy wstrzymać aż do chwili wystąpienia odpowiedniego zdarzenia. Dlatego też, jeżeli zachodzi konieczność przekazania argumentów funkcji wywoływanej przez procedurę obsługi zdarzeń lub obserwatora zdarzeń, to trzeba ją opakować wywołaniem funkcji anonimowej.
Przykład 12.3.
function myFunction(arg) {
// treść funkcji
}
var el = document.getElementById('id-elementu');
el.addEventListener('click', function() {myFunction(5);}, false);
12.4. Przepływ zdarzeń
Elementy HTML są zagnieżdżane w innych elementach. Jeżeli na przykład klikniemy łącze, to klikniemy także elementy nadrzędne tego łącza. JavaScript wywoła zdarzenia w danym elemencie oraz we wszystkich elementach wewnątrz których znajduje się ten element. Kolejność wywoływania zdarzeń nosi nazwę przepływu zdarzeń, a zdarzenia poruszają się w obu kierunkach:
- propagacja zdarzeń - na początku zdarzenie znajduje się w najbardziej szczegółowym węźle, a następnie przepływa na zewnątrz do najbardziej szczegółowego - jest to domyślny typ przepływu zdarzeń powszechnie obsługiwany przez przeglądarki internetowe (w metodzie addEventListener() ostatni argument ustawiamy na false);
- przechwytywanie zdarzeń - na początku zdarzenie znajduje się w najmniej szczegółowym węźle, a następnie przepływa do wewnątrz do najbardziej szczegółowego - ten typ przepływu zdarzeń nie jest obsługiwany przez IE 8 oraz jej wcześniejsze wersje (w metodzie addEventListener() ostatni argument ustawiamy na true).
Przykład 12.4.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Przykład</title>
<style>
#page {
background-color: lightpink;
margin: 30px;
float: left;
width: 400px;
}
a {
cursor: pointer;
}
</style>
</head>
<body>
<div id="page">
<h1>Lista</h1>
<h2>Propagacja</h2>
<ul id="list">
<li id="item"><a id="link">Przykład</a></li>
</ul>
</div>
<div id="page">
<h1>Lista</h1>
<h2>Przechwytywanie</h2>
<ul id="list2">
<li id="item2"><a id="link2">Przykład</a></li>
</ul>
</div>
</body>
</html>
JavaScript:
function showElement() {
alert(this.innerHTML);
}
var el = document.getElementById("list");
el.addEventListener('click', showElement, false);
el = document.getElementById("item");
el.addEventListener('click', showElement, false);
el = document.getElementById("link");
el.addEventListener('click', showElement, false);
el = document.getElementById("list2");
el.addEventListener('click', showElement, true);
el = document.getElementById("item2");
el.addEventListener('click', showElement, true);
el = document.getElementById("link2");
el.addEventListener('click', showElement, true);
12.5. Obiekt zdarzenia
Kiedy zdarzenie występuje, obiekt event przekazuje informacje o danym zdarzeniu i elemencie, w którym zostało ono wywołane. Obiekt zdarzenia jest przekazywany do każdej funkcji zdefiniowanej w procedurze obsługi lub obserwatorze zdarzenia. Jeżeli zachodzi potrzeba przekazania argumentów do nazwanej funkcji , to obiekt event będzie w pierwszej kolejności przekazywany do anonimowej funkcji opakowania (odbywa to się automatycznie). Następnie trzeba ją podać jako parametr funkcji nazwanej. Kiedy obiekt event jest przekazywany funkcji, to często otrzymuje parametr o nazwie e; to powszechnie stosowany skrót.
Właściwości i metody obiektu event
Właściwości:
- target - wskazuje element docelowy dla zdarzenia;
- type - typ wywołanego zdarzenia;
- cancelable - wskazuje, czy można anulować domyślne zachowanie elementu.
Metody:
- preventDefault() - anuluje domyślne zachowanie zdarzenia (o ile istnieje taka możliwość);
- stopPropagation() - uniemożliwia zdarzeniu dalszą propagację lub przechwytywanie.
Przykład 12.5.
Obserwator zdarzeń bez parametrów:
function myFunction(e) {
var target = e.target;
}
var el = document.getElementById('id-elementu');
el.addEventListener('click', myFunction, false);
Obserwator zdarzeń z parametrami:
function myFunction(e, arg) {
var target = e.target;
}
var el = document.getElementById('id-elementu');
el.addEventListener('click', function(e) {myFunction(e, 5);}, false);
12.6. Słowo kluczowe this
Podczas wywoływania funkcji, użycie właściwości target obiektu event to najlepszy sposób ustalenia, w którym elemencie wystąpiło zdarzenie. Takie podejście zostało omówione poniżej i opiera się na słowie kluczowym this.
Przykład 12.6.
Słowo kluczowe this odwołuje się do właściciela funkcji. W kodzie poniżej this odwołuje się do elementu, w którym wystąpiło zdarzenie:
function checkUsername() {
var elMsg = document.getElementById('feedback');
if (this.value.length < 5) {
elMsg.innerHTML = 'Nazwa użytkownika jest zbyt krótka.';
}
else {
elMsg.innerHTML = '';
}
}
var el = document.getElementById('username');
el.addEventListener('blur', checkUsername, false);
Takie rozwiązanie działa, kiedy funkcji nie są przekazywane żadne parametry (i dlatego nie jest wywoływana z poziomu funkcji anonimowej).
Przykład 12.7.
function checkUsername(el, minLength) {
var elMsg = document.getElementById('feedback');
if (el.value.length < minLength) {
elMsg.innerHTML = 'Nazwa użytkownika jest zbyt krótka.';
}
else {
elMsg.innerHTML = '';
}
}
var el = document.getElementById('username');
el.addEventListener('blur', function() {checkUsername(el, 5);}, false);
W obu powyższych przykładach preferowanym podejściem jest użycie obiektu event.
12.7. Zdarzenia interfejsu użytkownika
Zdarzenia interfejsu użytkownika są skutkiem interakcji z oknem przeglądarki, a nie wyświetlaną przez nią stroną HTML - może to być na przykład wczytanie stronu lub zmiana wymiarów okna przeglądarki.
- Zdarzenie load - wywoływane po pełnym wczytaniu strony internetowej. Zdarzenie to jest wywoływane także w węzłach innych elementów przeznaczonych do wczytania, takich jak obrazy, skrypty i obiekty. Według specyfikacji DOM Level 2 (listopad 2000) omawiane zdarzenie jest wywoływane w obiekcie document, choć wcześniej było wywoływane w obiekcie window. W celu zapewnienia wstecznej zgodności przeglądarki obsługują oba podejścia; programiści często dołączają procedury obsługi zdarzeń load do obiektu window (zamiast document).
- Zdarzenie unload - wywoływane podczas usuwania strony internetowej (najczęściej po wystąpieniu żądania pobrania nowej strony). Według specyfikacji DOM Model 2 omawiane zdarzenie jest wywoływane w węźle dla elementu body, ale w starszych przeglądarkach internetowych jest wywoływane w obiekcie window.
- Zdarzenie error - wywoływane, kiedy przeglądarka internetowa napotka błąd JavaScript lub gdy zasób nie istnieje. Obsługa tego zdarzenia jest niespójna w różnych przeglądarkach internetowych i dlatego nie stanowi ono niezawodnego sposobu obsługi błędów.
- Zdarzenie resize - wywoływane po zmianie wielkości okna przeglądarki internetowej. Podczas zmiany wielkości okna przeglądarka stale wywołuje to zdarzenie. Dlatego lepiej unikać używania tego zdarzenia do wykonywania skomplikowanego kodu, ponieważ strona może być wówczas odebrana jako wolno reagująca na działania użytkownika.
- Zdarzenie scroll - wywoływane po przewinięciu zawartości strony w górę lub w dół. Może odnosić się do całej strony lub określonego elementu na stronie. Podczas przewijania zawartości okna przeglądarka nieustannie wywołuje to zdarzenie. Dlatego lepiej unikać tego zdarzenia do wykonywania skomplikowanego kodu, gdy użytkownik przewija zawartość strony.
12.8. Zdarzenia aktywności
Elementy HTML, z którymi użytkownik prowadzi interakcję, na przykład łącza, mogą stawać się aktywne. Istnieją zdarzenia wywoływane aktywacją lub dezaktywacją elementów.
- Zdarzenie focus - wywoływane, kiedy element staje się aktywny.
- Zdarzenie blur - wywoływane, kiedy element staje się nieaktywny.
12.9. Zdarzenia myszy
Zdarzenia myszy są wywoływane podczas poruszania myszą oraz klikania jej przyciskami.
- Zdarzenie click - wywoływane, kiedy użytkownik kliknie podstawowym przyciskiem myszy. Zdarzenie click będzie wywoływane dla elementu, nad którym aktualnie znajduje się kursor myszy. Zostanie wywołane także wtedy, gdy użytkownik naciśnie klawisz Esc na klawiaturze, kiedy element jest aktywny.
- Zdarzenie dblclick - wywoływane, kiedy użytkownik w krótkim odstępie czasu dwukrotnie kliknie podstawowym przyciskiem myszy.
- Zdarzenie mousedown - wywoływane, kiedy użytkownik wciśnie dowolny przycisk myszy.
- Zdarzenie mouseup - wywoływane, kiedy użytkownik zwolni przycisk myszy.
- Zdarzenie mouseover - wywoływane, kiedy kursor znajdował się na zewnątrz elementu i został umieszczony nad elementem.
- Zdarzenie mouseout - wywoływane, kiedy kursor jest nad elementem, a następnie zostaje przeniesiony na inny - na zewnątrz elementu bieżącego lub jego elementów potomnych.
- Zdarzenie mousemove - wywoływane, podczas poruszania kursorem nad elementem. To zdarzenie jest wywoływane nieustannie.
12.10. Zdarzenia klawiatury
Zdarzenia klawiatury są wywoływane, gdy użytkownik korzysta z klawiatury.
- Zdarzenie input - wywoływane podczas zmiany wartości elementu input lub textarea. Obsługiwane po raz pierwszy w IE 9.
- Zdarzenie keydown - wywoływane gdy użytkownik naciśnie dowolny klawisz na klawiaturze. Jeżeli klawisz będzie przetrzymany, zdarzenie będzie wywoływane nieustannie. To jest bardzo ważne, ponieważ dokładnie powiela zachowanie w polu tekstowym, kiedy użytkownik przetrzyma naciśnięty klawisz (ten sam znak będzie nieustannie wstawiany w polu tekstowym).
- Zdarzenie keypress - wywoływane gdy użytkownik naciśnie klawisz, co spowoduje wyświetlenie na ekranie odpowiedniego znaku. Zdarzenie to nie będzie wywoływane na przykład po naciśnięciu klawisza kursora choć wspomniany znak powoduje wywołanie zdarzenia keydown. Jeżeli użytkownik przytrzyma naciśnięty klawisz, zdarzenie będzie wywoływane nieustannie.
- Zdarzenie keyup - wywoływane gdy użytkownik zwalnia klawisz na klawiaturze. Zdarzenia keydown i keypress są wywoływane przed wyświetleniem znaku na ekranie, podczas gdy keyup już po jego wyświetleniu.
Który klawisz został naciśniety?
Kiedy używamy zdarzeń keydown lub keypress, obiekt event posiada właściwość o nazwie keyCode. Można ją wykorzystać do ustalenia, który klawisz został naciśnięty. Jednak wartością zwrotną nie będzie litera przyporządkowana danemu klawiszowi, lecz kod ASCII przedstawiający małą literę odpowiadającą temu klawiszowi. Jeżeli chcemy pobrać rzeczywistą literę lub cyfrę (zamiast kodu ASCII), obiekt String zawiera odpowiednią metodę o nazwie fromCharCode(), która przeprowadza odpowiednią konwersję: String.fromCharCode(event.keycode);
12.11. Zdarzenia dotyczące zmian i obserwatory
Dodanie lub usunięcie elementu z modelu DOM powoduje zmianę jego struktury. Zmiana ta wywołuje zdarzenie dotyczące zmian.
- Zdarzenie DOMNodeInserted - wywoływane po wstawieniu węzła w drzewie modelu DOM.
- Zdarzenie DOMNodeRemoved - wywoływane po usunięciu węzła z drzewa modelu DOM.
- Zdarzenie DOMSubtreeModified - wywoływane po zmianie struktury modelu DOM - po dwóch wyżej wymienionych zdarzeniach.
- Zdarzenie DOMNodeInsertedIntoDocument - wywoływane po wstawieniu węzła w drzewie modelu DOM jako węzła potomnego innego węzła, znajdującego się w dokumencie.
- Zdarzenie DOMNodeRemovedFromDocument - wywoływane po usunięciu węzła w drzewie modelu DOM jako węzła potomnego innego węzła, znajdującego się w dokumencie.
Przykład 12.8.
var elList, addLink, newEl, newText, counter, listItems; // Deklaracja zmiennych.
elList = document.getElementById('list'); // Pobranie listy.
addLink = document.querySelector('a'); // Pobranie przycisku dodawania elementu.
counter = document.getElementById('counter'); // Pobranie elementu licznika.
function addItem(e) { // Deklaracja funkcji.
e.preventDefault(); // Uniemożliwienie akcji łącza.
newEl = document.createElement('li'); // Nowy element <li>.
newText = document.createTextNode('Nowy element listy'); // Nowy węzeł tekstowy.
newEl.appendChild(newText); // Dodanie tekstu do elementu <li>.
elList.appendChild(newEl); // Dodanie elementu <li> do listy.
}
function updateCount() { // Deklaracja funkcji.
listitems = list.getElementsByTagName('li').length; // Ustalenie całkowitej liczby elementów <li>.
counter.innerHTML = listitems; // Uaktualnienie licznika.
}
addLink.addEventListener('click', addItem, false); // Kliknięcie przycisku.
elList.addEventListener('DOMNodeInserted', updateCount, false); // Model DOM uaktualniony.
Zadania domowe
Na kolejne zajęcia musi być wykonana czwarta faza projektu - “ożywienie” aplikacji przy pomocy języka JavaScript.
Źródła
- Duckett Jon, JavaScript and JQuery: Interactive Front-End Web Development, przeł. Robert Górczyński, Helion, 2015, ISBN 978-83-283-0126-9.
- kursjs.pl