Rad sa JavaScriptom i DOM događajima
Ovo je tema koja se u literaturi često pogrešno interpretira kao JavaScript događaji (JavaScript events), iako suštinski spada u web DOM programiranje. Događaji su neke aktivnosti koje se mogu desiti na web stranici. Najčešće su to aktivnosti samog korisnika (npr. klik mišem), ali isto tako mogu biti i nešto što se dešava bez njegovog uticaja (npr. učitavanje stranice).
Drugim rečima, programiranje više nije pisanje programa koji se izvršava od početka do kraja, već pisanje funkcija obrade događaja (event handler) koje se izvršavaju kao "reagovanje" na određene događaje (npr. otvaranje prozora, klik na dugmence i sl).
Postoji više načina da definišemo obradu događaja u našoj web aplikaciji.
Definisanje događaja preko HTML parametara
Ovaj način je najmanje preporučljiv, ali i najjednostavniji za početnike. Smatra se lošom praksom zbog toga što se mešaju HTML kod (opis stranice) i delovi programa (ponašanje) - pa makar to bili i samo pozivi funkcija.
Inače, definisanje događaja na ovaj način je krajnje jednostavno. U HTML-u postoji veliki broj opštih parametara (koji mogu da se ubace u svaki HTML element), i koji predstavljaju parametre događaja. U tabeli su navedeni neki od njih.
Događaji miša | |
---|---|
onclick | Klik mišem |
onmousedown | Pritisak dugmeta miša |
onmouseup | Otpuštanje dugmeta miša |
ondblclick | Dupli klik mišem |
onmouseover | Dovođenje miša iznad elementa |
onmouseout | Uklanjanje miša sa elementa |
onmousemove | Pomeranje miša dok je nad elementom |
Događaji tastature | |
onkeypress | Kucanje jednog tastera |
onkeydown | Pritisak tastera |
onkeyup | Otpuštanje tastera |
Događaji stranice | |
onload | Resurs (sa svim podelementima) je učitan (npr. stranica je kompletno učitana) |
onerror | Resurs nije učitan (npr. slika ne postoji) |
onunload | Resurs se uklanja iz memorije (npr. prelazak na neku drugu stranicu, reload) |
onabort | Prekinuto učitavanje |
onresize | Okvir dokumenta je promenio veličinu |
onscroll | Dokument (ili element) je skrolovan |
onselect | Selektovan je neki deo dokumenta |
Znači, izaberemo elemenat za koji želimo da definišemo reagovanje na neki događaj i dodamo mu parametar događaja. Kao vrednost ovako navedenog parametra se ustvari zadaju JavaScript naredbe, koje se izvršavaju kada se desi zadati događaj. Preporučujemo da na ovom mestu navodite samo poziv funkcije, koja je deklarisana na nekom drugom mestu (zajedno sa ostatkom programa), kako biste držali HTML što je moguće "čistijim".
<element događaj="javascript"> ...sadržaj... </element>
Primer
Recimo da se na jednom mestu nalazi JavaScript program i da je u njemu deklarisana funkcija fun() koja bi trebalo da se aktivira u trenutku kada korisnik klikne mišem na određeni DIV blok. Ta funkcija može raditi bilo šta sa tim blokom ili bilo kojim drugim elementom stranice - ili čak ne raditi ništa što je vidljivo korisniku.
function fun(){
// obrada događaja - naredbe koje se izvršavaju kada se događaj desi
}
Na stranici imamo taj DIV blok koji "dočekuje" klik mišem. Da bi mogao da odreaguje na kliktanje, dodajemo mu poseban parametar onclick. Kao vrednost parametra bismo mogli da smestimo više JavaScript naredbi, ali najpreporučljivije je da samo pozovemo funkciju koja radi sve ostalo. Tako imamo samo jednu naredbu koja predstavlja poziv funkcije fun().
<div onclick="fun()">
...bilo kakav sadržaj div bloka
</div>
Znači, funkcija obrade događaja, sama po sebi nije nikako specijalno "obeležena". Ona jeste funkcija obrade samo zato što smo napravili da se poziva kada korisnik klikne na DIV blok.
Ako je potrebno da naša funkcija "zna" nad kojim elementom se aktivirao događaj, korišćenjem objekta this, možemo na jednostavan način proslediti referencu na sam elemenat. Funkcija može "primiti" ovaj objekat preko parametra.
function fun(elemenat) {
// obrada događaja - parametar "elemenat"
// predstavlja referencu na objekat na koji je kliknuto
}
U samom pozivu funkcije, zadajemo objekat this kao parametar i on se u tom slučaju odnosi upravo na elemenat na koji je kliknuto. Funkcija onda "hvata" taj objekat preko parametra "elemenat".
<div onclick="fun(this)">
...sadržaj div bloka
</div>
Bojenje teksta elementa
Na primer, ako bismo želeli da obojimo tekst onog elementa na koji je korisnik kliknuo mišem, uradili bismo to ovako:
<script>
function boja(elemenat) {
elemenat.style.color = "red";
}
</script>
<div onclick="boja(this)">
Prvi blok
</div>
<div onclick="boja(this)">
Drugi blok
</div>
Kao što vidite, postoje dva DIV bloka i za svaki je definisan događaj onclick. U oba se poziva ista funkcija boja(), kojoj se kao argument prosleđuje objekat this. Kada se klikne na prvi DIV blok, this predstavlja referencu na njega, a ako se klikne na drugi blok, onda this referencira taj elemenat.
Funkcija boja() prima referencirani DIV blok u obliku parametra elemenat. Dakle, sve što radimo sa objektom elemenat unutar funkcije, odraziće se na DIV blok na koji je korisnik kliknuo.
Direktno referenciranje funkcije
Kao što HTML elementi imaju parametre događaja, tako i objekti elemenata u JavaScriptu imaju metode obrade događaja. Ovo su u stvari svojstva - reference na funkcije koje obrađuju događaj (event handler).
element.događaj = funkcija_obrade;
Funkcija obrade može biti data kao referenca na neku već postojeću funkciju:
element.događaj = funkcija;
A može biti i tu odmah deklarisana anonimna (ili čak i imenovana) funkcija:
element.događaj = function() {...};
element.događaj = function naziv() {...};
Uklanjanje funkcije obrade je jednostavno - prosto ukidamo referencu.
element.događaj = null;
Primer
Funkcija obrade događaja može biti "klasična" imenovana ili anonimna funkcija. U oba slučaja, da bismo je povezali sa elementom, moramo nekako da "dohvatimo" taj element sa stranice. Poslužla bi nam bilo kakva referenca na element, a ovde koristimo metod getElementById(), objekta document. Kao parametar navodimo identifikaciju HTML elementa. Tako će rezultat ovog metoda biti referenca na taj elemenat, a na to slobodno možemo da "nakačimo" svojstvo onclick.
document.getElementById("blok").onclick = function() {
// obrada događaja
}
<div id="blok">
...sadržaj div bloka
</div>
U ovom slučaju smo funkciju obrade događaja naveli kao anonimnu funkciju.
Inače se funkcija obrade događaja poziva u kontekstu elementa nad kojim se aktivirao događaj, što znači da unutar funkcije objekat this referencira sam taj elemenat.
Primer bojenja teksta
Pogledajmo primer sa bojenjem teksta elementa na koji je korisnik kliknuo. I u ovom slučaju smo se odlučili za kreiranje nezavisne funkcije boja(). Kao što vidimo, sada ne postoji potreba da funkcija ima parametar. Unutar ove funkcije takođe menjamo boju teksta elementa na koji je kliknuto, ali vidimo da sada to radimo korišćenjem objekta this. Kada se funkcija obrade pozove, unutar nje, objekat this označava elemenat za koji je pozvana.
<script>
function boja() {
this.style.color = "red";
}
// mora da bude unutar funkcije događaja
window.onload = function() {
document.getElementById("prvi").onclick = boja;
document.getElementById("drugi").onclick = boja;
}
</script>
<div id="prvi">
Prvi blok
</div>
<div id="drugi">
Drugi blok
</div>
Povezivanje onclick događaja elementa i funkcije boja() se obavlja tako što "dohvatamo" element metodom getElementById() i njegovo svojstvo onclick referenciramo na funkciju boja(). Ali ovo nije jedina funkcija obrade koju imamo! Pogledajte - i objektu window smo dodali funkciju za događaj onload - znači, nešto će da se desi kada se dokument učita. To što se dešava je definisano u anonimnoj funkciji koju smo referencirali svojstvom onload. Na tom mestu se DIV blokovima definiše onclick događaj.
Zašto povezivanje funkcije obrade mora da bude takođe unutar funkcije i to vezane za onload događaj objekta window? Pa ako je HTML dokument sklopljen na ovakav način, i ako bismo ostavili da referenciranje funkcije boja() za onclick svojstvo "visi" van funkcije, imali bismo grešku, pošto bi povezivanje bilo pokušano čim web čitač naiđe na te naredbe, odnosno, čak i pre nego što se učitaju blokovi "prvi" i "drugi".
Ovako, kada se sve učita, poziva se događaj onload za objekat window i tada se izvršava funkcija u kojoj se vrši povezivanje. Drugo rešenje bi bilo kada bismo <script> odeljak smestili na kraj dokumenta. Pogledajte kako smo to rešili u primeru...
Dodavanje funkcije obrade
Za svaki elemenat možemo pozvati metod addEventListener() kojim možemo dodati funkciju obrade (event handler) za neki događaj.
I ovde, funkcija obrade može biti navedena svojim nazivom (referencom), ili kao anonimna funkcija.
element.addEventListener("događaj", funkcija_obrade);
Obratite pažnju, iako se HTML parametar zove "onNešto", a takođe se i svojstvo elementa isto tako zove "onnešto", sam događaj je uvek samo "nešto". Znači ako želimo da dodamo funkciju događaja za klik mišem to neće biti "onclick", već samo "click".
Ovo je najbolji i najpreporučljiviji način dodavanja događaja.
Za uklanjanje dodeljene funkcije obrade, koristimo metod removeEventListener().
element.removeEventListener("događaj", funkcija_obrade);
Imamo još jednu preporuku - ako nameravate da kasnije u programu uklanjate funkcije obrade iz elementa, nemojte koristiti anonimnu funkciju kada dodajete event handler, pošto kasnije morate identifikovati tu istu funkciju radi uklanjanja.
Primer
Sve je vrlo slično prethodnom načinu povezivanja funkcija obrade, ali je za nijansu komplikovanije. Opet moramo da "dohvatimo" elemenat iz dokumenta preko njegove identifikacije, jedino što sada ne referenciramo direktno funkciju obrade, već je prosleđujemo metodu addEventListener().
document.getElementById("blok").addEventListener("click", function() {
// obrada događaja
} );
<div id="blok">
...sadržaj div bloka
</div>
Isto kao i u prethodnom slučaju, funkciju obrade smo dodali kao anonimnu funkciju, a sama funkcija obrade događaja se poziva u kontekstu elementa, što znači da unutar funkcije objekat this referencira taj elemenat.
Primer sa promenom boje izgleda jako slično.
<script>
function boja() {
this.style.color = "red";
}
window.addEventListener("load", function() {
document.getElementById("prvi").addEventListener("click", boja);
document.getElementById("drugi").addEventListener("click", boja);
});
</script>
<div id="prvi">
Prvi blok
</div>
<div id="drugi">
Drugi blok
</div>
- Mozilla Developer Network, Event reference
- Mozilla Developer Network, EventTarget.addEventListener()