Kurs: - Core JavaScript Programming
Modul: Rukovanje objektima
Autor: Vladimir Marić
Naziv jedinice: Rukovanje događajima
Materijali vezani uz ovu lekciju:
-
Test rukovanje događajima -
Rukovanje događajima (PDF dokument)
Ako bi dosadašnje lekcije iz oblasti DOM-a okarakterisali kao motor JavaScrip-a u pretraživaču, onda bi događaji – event-i, svakako bili gorivo za taj motor.
Recimo da pretraživač, od trenutka kada emituje web stranu, konstantno “sluša” sve objekte koji se na njoj nalaze, a pri tom, svaki od objekata poseduje određeni set atributa koji se slušaju. Na primer, šta se sve može dogoditi jednom tasteru? Može biti pritisnut ili otpušten, može se mišem preći ili prevući preko njega... Tekst boks, sa druge strane, može pored toga pretrpeti i upis teksta. To su sve događaji koje pretraživač može da prepozna, jer su podrazumevani u deklaraciji tih objekata i njihovo pojavljivanje je, u stvari, trenutak kada mi nastupamo. Naravno, samo pod uslovom da smo pre toga, negde u našem programu dali do znanja pretraživaču da želimo da nam se „raportira” za određeni događaj, odnosno, da nam se da na uvid da se on dogodio.
Iako možda zvuči komplikovano, nakon svega do sada naučenog, ovaj deo će zapravo biti prilično jednostavan za razumevanje i implementaciju jer je u pitanju samo most između neke funkcionalnosti i objekata na strani.
Pogledajmo, za početak, jedan jednostavan primer:
<div onclick="alert('radi')">proba</div>
Ovaj div Tag ima atribut onclick. Vrednost tog atributa je JavaScript kod. Kada dođe do događaja na koji atribut ukazuje (a u ovom slučaju to je klik, odnsno, pritisak levog tastera miša iznad div taga), skripta će se izvršiti.
I to je ujedno (pored, naravno, liste događaja koje jedan objekat može da sluša) i sve što je potrebno da znamo da bismo mogli da rukujemo događajima.
Događaji i funkcije
Prethodni primer, dobar je ako hoćemo da naša skripta iscrta boks sa porukom, ali ako bismo želeli nešto ozbiljniju logiku koju bi pokrenuo određeni događaj, ovaj pristup ne bi bio dovoljan, jer bismo morali da pišemo mnogo linija koda odvojenih tačkom i zarezom u samo jednom atributu. Sledeća linija je prikaz loše prakse:
<div onclick="alert('prva linija'); alert('druga linija');">proba</div>
Umesto toga, logiku treba smestiti u posebnu funkciju, koju treba pozivati iz inicijalizacije događaja. Sledeći primer je dobar:
<script>
function obradaKlika()
{ alert("prva linija");
alert("druga linija");}
</script>
<div onclick="obradaKlika()">proba</div>
Ako se podsetimo, u jednoj od prvih lekcija smo pominjali da se u JavaScript-u funkcionalnost smešta u head deo HTML-a, jer se on dekodira prvi, a stvari u koje su nam potrebne u realnom vremenu, tokom iscrtavanja strane, u body deo. U tom trenutku, mislili smo baš na ovakav slučaj. Funkcija obradaKlika() treba da bude smeštena u head deo, jer treba da bude inicijalizovana pre nego što dođe do inicijalizacije svih ostalih elemenata strane, da se ne bi dogodilo da događaj poziva nepostojeću funkciju.
Sada ostaje da se reši još samo jedan problem, a to je, kako proslediti kontekst u funkciju. Pogledajmo malo modifikovan prethodni primer:
<script>
function obradaKlika()
{ alert(document.getElementById("mojDiv").innerHTML); }
</script>
<div id="mojDiv" onclick="obradaKlika()">proba</div>
Ovaj primer nije dobar, jer je objekat u funkciji hard kodiran i funkcija je upotrebljiva samo za jedan jedini Tag na strani (mojDiv). Nešto fleksibilnija varijanta bila bi kada bi u funkciju uveli i parametar
<script>
function obradaKlika(obj)
{ alert(document.getElementById(obj).innerHTML);}
</script>
<div id="mojDiv" onclick="obradaKlika('mojDiv')">proba</div>
U ovom slučaju premestili bismo statički deo iz funkcije u Tag i znatno bi optimizovali kod. Primećujemo da je string parametar u pozivu funkcije obradaKlika (mojDiv), postavljen u jednostruke navodnike. To je, naravno, zbog toga što se ceo poziv već nalazi u dvostrukim navodnicima, a u HTML-u nije moguće staviti jedne dvostruke navodnike u druge. Ovaj problem rešavamo stavljanjem jednostrukih navodnika u dvostruke (ili obrnuto, dvostrukih u jednostruke) što je princip koji je HTML u stanju da podnese, a pored toga i JavaScript ne pravi razliku između jednostrukih i dvostrukih navodnika.
Iako je prethodni primer visoko funkcionalan i dalje nije potpuno dinamičan. Naime, moramo i dalje, prilikom svakog poziva funkcije, navoditi tačan naziv Tag-a koji je poziva. Da bismo prevazišli i ovo, možemo proslediti funkciji ceo objekat (kontekst). U tom slučaju, rešili smo se statičkih elemenata u potpunosti i možemo dalje praviti Tag-ove bez razmišljanja o eksplicitnom pozivanju funkcije. S obzirom da iz lekcije sa prototipovima znamo da se kontekst označava sa ključnom rečju this, tu ćemo reč i upotrebiti kao parametar za funkciju obradaKlika().
U narednom primeru primećujemo da ne postoje više id atributi div Tag-ova kao i da se div Tag-ovi razlikuju samo po sadržaju, dok su pozivi:
<script>
function obradaKlika(obj)
{ alert(obj.innerHTML); }
</script>
<div onclick="obradaKlika(this)">proba</div>
<div onclick="obradaKlika(this)">proba1</div>
<div onclick="obradaKlika(this)">proba2</div>
Onog trenutka kada izazovemo neki događaj JavaScript automatski pravi i objekat tipa Event i u njega smešta razne parametre vezane za taj događaj. Na primer, koja je bila pozicija kurzora u trenutku događaja, tip događaja (klik, pritisak tastera...), objekat koji je izazvao događaj... Neke od ovih informacija mogu biti veoma bitne, npr. kada želimo da rukujemo sa poljima za unos teksta i kada želimo da pratimo svaki korak unosa:
<script>
function kp(e)
{ document.getElementById("izlaz").innerHTML+=String.fromCharCode(e.keyCode); }
</script>
<input type="text" onkeypress="kp(event)" />
<div id="izlaz"></div>
Ovaj primer prati svaki karakter unešen u tekst boks i ispisuje ga u div Tag koji se zove izlaz.
Po istom principu, mogli bismo detektovati pritisak tastera Enter na svakom tekst boksu i tako izvršiti aktivacuju određene akcije.

Na sajtu sa slike (isečen je, naravno, samo deo sajta) postoje dva odeljka na unos na jednoj strani. Jedan je login korisnika, a drugi prijava e-mail adrese. S obzirom na to da podrazumevani taster na strani može biti samo jedan, problem bi se pojavio kada bi korisnik vršio unos korisničkog imena i šifre, zatim pritisnuo enter, a umesto tastera POTVRDI aktivirao se taster PRIJAVI ME zato što je, recimo, njemu dodeljeno podrazumevano svojstvo.
Ovaj problem se rešava na način vrlo sličan malopređašnjem primeru:
<script>
function kp(o,e)
{ if (e.keyCode == 13) alert("Pritisnut je enter na polju " + o.id); }
</script>
Potvrdi:
<input id="potvrdi" type="text" onkeypress="kp(this, event)" />
Prijavi me:
<input id="prijaviMe" type="text" onkeypress="kp(this, event)" />
Nakon ovoga, u jednoj funkciji imamo identifikovan objekat koji je inicirao funkciju i tako možemo odlučiti koju ćemo akciju izvršiti.
Jedan od bitnijih događaja je i onload događaj. Glavna „mušterija“ ovog događaja je body element web strane:
<body onload="alert('Strana je ucitana')" >
</body>
Nešto manje korišćen, a takođe prilično koristan događaj (koristi se na body Tag-u) je i onunload događaj. Iako, isprva, ovaj događaj deluje nesvrsishodno (jer, zašto bismo bilo šta radili, kada je strana već isključena), on je zapravo veoma koristan, jer je to jedini način da ispratimo trenutak kada je korisnik napustio našu stranu. Mogli bismo, na primer, kroz ovaj događaj, aktivirati neku AJAX akciju, koja će izvršiti apdejt statusa korisnika u nekom izvoru podataka.
Nazive događaja (Hendler) možete pisati na različite načine (onClick i onclick su isti događaji, ali se mogu zapisati na različite načine zbog kompatibilnosti konvencija).
Treba znati da ne mogu svi događaji da reaguju na sve kontrole (npr. onresize može biti primenjen samo na window objekat)
Evo liste svih HTML (XHTML) događaja i njihovih objašnjenja:
onabort – Image (prekid učitavanja slike)
<img src="mojaSlika.gif" onabort="alert('ucitavanje je prekinuto')" />
onblur - Button, Checkbox, FileUpload, Layer, Password, Radio, Reset, Select, Submit, Text, TextArea, Window (gubljenje fokusa na kontroli)
<input type="text" onblur="alert('izgubljen je fokus')" />
onchange - FileUpload, Select, Text, TextArea (Promenjen je sadržaj elementa (zahteva izlazak iz fokusa))
<input type="text" onchange="alert('Sadrzaj je promenjen')" />
onclick - Button, Document, Checkbox, Link, Radio, Reset, Submit (izvršen je klik na objektu)
<div onclick="alert('pritisnuto')">pritisni</div>
ondblclick - Document, Link (izvršen je dupli klik na objektu)
<div ondblclick="alert('pritisnuto dva puta')">pritisni</div>
onerror - Image, Window (JavaScript greška)
<img src="slikaKojaNePostoji.gif" onerror="alert('Greska pri ucitavanju')" />
onfocus - Button, Checkbox, FileUpload, Layer, Password, Radio, Reset, Select, Submit, Text, TextArea, Window (objekat je dobio fokus)
<input type="text" onfocus="alert('fokus')" />
onkeydown - Document, Image, Link, TextArea (pritisnut je taster)
<input type="text" onkeydown="alert(String.fromCharCode(event.keyCode))" />
onkeypress - Document, Image, Link, TextArea (taster je pritisnut, ali ne i pušten)
<input type="text" onkeypress="alert(String.fromCharCode(event.keyCode))" />
onkeyup - Document, Image, Link, TextArea (taster je pritusnut pa pušten)
<input type="text" onkeyup="alert(String.fromCharCode(event.keyCode))" />
onload - Image, Window (završeno je učitavanje)
<body onload="alert('strana je ucitana')"></body>
onmousedown - Button, Document, Link (pritisnut je taster miša)
<div onmousedown="alert('Izvrseno je pritiskanje misa')">pritisni</div>
onmousemove – Image (kretanje mišem iznad objekta)
<img width=100 height=100 src="mojaSlika.gif" onmousemove="document.getElementById('rez').innerHTML='x: ' + event.x + ' y: ' + event.y" /><div id="rez"></div>
onmouseout - Image, Link (napuštanje objekta mišem)
<div style="border: 1px solid" onmouseout="alert('Zona je napustena')">pristupi</div>
onmouseover - Image, Link (prelazak mišem preko objekta)
<div style="border: 1px solid" onmouseover="alert('Mis je pristupio zoni slusanja')">pristupi</div>
onmouseup - Button, Document, Link (pritiskanje tastera miša)
<div style="border: 1px solid" onmouseup="alert('Taster misa je pusten')">pritisni - pusti</div>
onreset – Form (reset web forme)
<form onreset="alert('izvrsen reset')">
<input type="text" />
<input type="reset" value="reset" />
</form>
onresize – Window (menjanje veličine prozora ili okvira)
<body onresize="alert('Promena velicine')"></body>
onselect - Text, Textarea (selektovan je tekst u polju)
<input onselect="alert('selekcija je izvrsena')" type="text" />
onsubmit – Form (pritisnut je submit taster forme)
<form onsubmit="alert('izvrsen submit')"><input type="submit" value="submit" /></form>
onUnload – Window (strana je napuštena)
<body onunload="alert('strana je napustena')"></body>
Takođe, evo i nekih atributa objekata događaja:
altKey, shiftKey – informacija o pritisnutim tasterima prilikom klika
<div onclick="alert('shift: ' + event.shiftKey + '\nalt: ' + event.altKey + '\nctrl: ' + event.ctrlKey)">PRITISNI</div>
button ili which (ff) – Koji taster miša je pritisnut
<div onmousedown="alert(event.button)">PRITISNI</div>
clientX, clientY ili x,y (ff) – Koordinate kurzora u trenutku događaja, u odnosu na prozor
<div onmousedown="alert(event.screenX)">PRITISNI</div>
screenX, screenY – Koordinate kurzora u trenutku događaja, u odnosu na ekran
<div onmousedown="alert('x: ' + event.screenX + 'y: ' + event.screenY)">PRITISNI</div>
type – Tip događaja
<div onclick="alert(event.type)">PRITISNI</div>
keyCode – Kod pritisnutog tastera
<input type="text" onkeydown="alert(String.fromCharCode(event.keyCode))" />
Vežba 1
Problem:
Dat je sledeći kod:
var capt = false;
var mDiv = document.createElement("div");
mDiv.style.border="1px solid black";
mDiv.style.position="absolute";
mDiv.style.top="0px";
mDiv.style.left="0px";
document.body.appendChild(mDiv);
Potrebno je dopuniti kod, tako da, kada korisnik pritisne levi taster miša, veličina div taga se modifikuje u odnosu na poziciju miša, a nakon ponovnog pritiskanja tastera, div ostaje fiksiran na trenutnoj veličini.
Rešenje:
var capt = false;
var mDiv = document.createElement("div");
mDiv.style.border="1px solid black";
mDiv.style.position="absolute";
mDiv.style.top="0px";
mDiv.style.left="0px";
document.body.appendChild(mDiv);
function draw(e)
{
if(capt)
{
mDiv.style.width=e.clientX+"px";
mDiv.style.height=e.clientY+"px";
}
}
window.onmousemove = draw;
window.onclick = function() { if(capt) capt=false; else capt=true; }
Vežba 2
Problem:
Postoji sledeći niz (objekat):
var menuArr = {"Google":"http://www.google.com","Yahoo":"http://www.yahoo.com","Bing":"http://www.bing.com"};
Potrebno je napraviti funkciju koja prihvata taj niz i ciljni element kao parametre. Funkcija na osnovu priloženih parametara kreira meni. Svaka stavka menija ima pozadinsku boju žutu i boju teksta crnu. Prilikom prelaska mišem preko stavke menija, boja pozadine se menja u zelenu, a boja teksta u belu. Pritiskom na stavku menija, vrši se otvaranje željene strane.
Rešenje:
function createMenu(arr,parent)
{
for(i in arr)
{
var a = document.createElement("a");
a.href = arr[i];
a.innerHTML = i;
a.style.padding = "5px";
a.style.backgroundColor="yellow";
a.style.border = "1px solid black";
a.onmouseover = function() { this.style.backgroundColor="green"; this.style.color="white"; }
a.onmouseout = function() { this.style.backgroundColor="yellow"; this.style.color="black"; }
parent.appendChild(a);
}
}
var menuArr = {"Google":"http://www.google.com","Yahoo":"http://www.yahoo.com","Bing":"http://www.bing.com"};
createMenu(menuArr,document.body)
Vežba 3
Problem:
Postoji sledeći HTML kod:
...
<body>
<input type='text' id='myText' />
</body>
Potrebno je obezbediti da nakon učitavanja strane, kontrola myText automatski bude aktivna.
Rešenje:
...
<body onload="document.getElementById('myText').focus();" >
<input type='text' id='myText' />
</body>
Najvažnije iz lekcije
- Događaji HTML objekata i rukovanje čine suštinu JavaScripta.
- Događaje izazivaju HTML objekti, ali ih obrađujemo kroz JavaScript.
- Najbolja praksa je obrada događaja kroz JavaScript funkcije.
- Prilikom izazivanja događaja, nastaje i objekat tog događaja (event) koji poseduje određene atribute.
- Kontekst objekta koji je izazvao događaj, predstavlja se ključnom rečju this.