Events vormen het hart van een Javascript-pagina. Event-handling staat toe dat de Javascript opdrachten op het juiste moment worden uitgevoerd, wanneer de juiste gebreurtenis heeft plaatsgevonden:
Een berekening wordt uitgevoerd wanneer een gebruiker op een knop klikt, een figuur verandert wanneer de gebruiker er met de muis over beweegt, een animatie wordt gestart wanneer de pagina geladen is ...
Een groot probleem met event-handling is dat browsers absoluut geen eenduidig meechanisme hebben om events af te handelen.
Hier vind je een overzicht van de belangrijkste events die je met Javascript op een webpagina kan afhandelen.
| Soort gebeurtenis | Beschrijving | Gebeurtenissen | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Muis | Reageren op muisacties van de gebruiker |
|
||||||||||||||||||
| Toets | Reageren op toetsaanslagen |
|
||||||||||||||||||
| Formulieren | Reageren op acties voor een formulier en formulierelementen |
|
||||||||||||||||||
| Interface | Acties als resultaat van gebruikersacties: vb. wanneer de gebruiker klikt op een formulierelement wordt dit element actief: het krijgt de focus. |
|
Nog veel meer events vind je bij MSDN (Microsoft).
Nu we een heel aantal events hebben leren kennen moeten we die events ook kunnen afhandelen op onze pagina's.
Algemeen kunnen we stellen dat een event kan worden afgehandeld met een event-handler die als naam het event heeft en een prefix 'on': onmouseover, onmouseout, onload, onfocus, onsubmit, ...
Een eerste manier om events af te handelen is inline-afhandeling. Deze manier van gebeurtenisafhandeling bestaat erin dat een event-handler wordt geplaatst als attribuut in de (X)HTML-tag.
Deze manier van werken is de oorspronkelijke manier van gebeurtenisafhandeling en wordt door alle browsers ondersteund.
Een nadeel aan deze manier van werken is dat de event-handlers in de (X)HTML-tag ingebed zijn en je dus een mengeling hebt van logische programmacode in Javascript en inhoud van je document (X)HTML.
Voor grotere toepassingen en voor specifieke taken kan dit vervelend zijn, en moeilijk in onderhoud.
<img src="../images/geiten.jpg" width="134" height="101"
alt="" border="0" onmouseover="alert('over de figuur');">
<a href="http://www.cnn.com"
onclick="alert('We surfen niet');return false">Surf naar CNN</a>
Wanneer je klikt op deze hyperlink wordt een alert getoond. De hyperlink wordt niet gevolgd doordat we de waarde false retourneren in onze event-handler, waardoor de standaardactie -het volgen van de link- niet wordt uitgevoerd.
Wanneer je vanuit je eigen event-handler false retourneert, wordt de standaardeventhandler niet uitgevoerd. Een uitzondering op deze regel is het tonen van een bericht in de statusbalk bij een onmouseover-actie: hier moeten we true retourneren, al willen we niet dat de gekoppelde url in de statusbalk verschijnt (mysterieus...).
<a href="../index.asp"
onmouseover="window.status='Terug naar startpagina';return true"
onmouseout="window.status=''">Cursusweb</a>
Voor hyperlinks bestaat zelfs de mogelijkheid javascript-code in het href-attribuut op te nemen:
<a href="javascript:alert('U heeft geklikt')">Klik me</a>
<div id="div1" style="width:100px;border:solid 1px"
onmouseover="doeIets(this)">Divisie 1</div><br>
<div id="div2" style="width:100px;border:solid 1px"
onmouseover="doeIets(this)">Divisie 2</div><br>
<script type="text/javascript">
<!--
function doeIets(obj)
{
var divId = obj.id;
alert('Muis over: ' + divId + '!')
}
-->
</script>
Met de stormachtige opkomst van DHTML was er nood aan een nieuw model voor event-handling.
De grote browsers ondersteunen dit model vanaf hun versie 4.
In dit model zijn de events volledig te benaderen vanuit Javascript: je hoeft geen code meer toe te voegen aan HTML-tags.
<div id="divtrad" style="width:100px;border:solid 1px" >Divisie</div>
<script type="text/javascript">
<!--
mijndiv = document.getElementById('divtrad');
mijndiv.onclick = muisKlik;
function muisKlik()
{
alert('Klik op divisie!');
}
-->
</script>
Je kan de event-handler koppelen vanuit Javascript-code en hoeft geen HTML-attribuut meer te gebruiken.
In dit vernieuwde event-model zijn event-handlers zoals onclick, onmouseover, onfocus, ... eigenlijk eigenschappen van elementen.
Merk op dat je de functie koppelt aan de event-handler zonder haakjes na de naam van de functie. Zet je daar wel haakjes, dan wordt het resultaat van de functie gekoppeld aan de event-handler in plaats van de functie zelf, dit is niet de bedoeling.
Gebruiken we de functie getObj uit dom.js (zie DOM) dan wordt dit:
<div id="divtrad" style="width:100px;border:solid" >Divisie</div> <script type="text/javascript"> <!-- mijndiv = new getObj('divtrad'); mijndiv.obj.onclick = muisKlik; function muisKlik() { alert('Klik op divisie!'); } --> </script>
Voor ondersteuning in Netscape4 is er nog een extra lijn code nodig om event-handlers te installeren. Je moet de methode captureEvents nog toepassen op het element.
mijndiv = new getObj('divtrad');
mijndiv.obj.onclick = muisKlik;
if (mijndiv.captureEvents) mijndiv.captureEvents(Event.CLICK)
Je kan nu zelfs event-handlers initiëren zonder dat de gebruiker daarvoor iets hoeft te doen:
mijndiv.onclick();
Dit stukje code zorgt ervoor dat de onclick event-handler van mijndiv wordt uitgevoerd. Dit zal resulteren in het uitvoeren van de functie muisKlik.
<a href="javascript:mijndiv.onclick()">Probeer het</a>
Microsoft heeft hiervoor nog een eigen methode ontwikkeld:
element.fireEvent('onclick');
Het sleutelwoord this kunnen we nu gebruiken binnen de functie die het event afhandelt. Op deze manier kunnen we een functie schrijven die bruikbaar is voor meerdere elementen en binnen de functie nagaan welk element de functie heeft aangeroepen.
<div id="test1" style="width:150px;border:solid 1px">Een testdivisie</div><br>
<div id="test2" style="width:150px;border:solid 1px">Nog een testdivisie</div>
<script type="text/javascript">
<!--
t1 = document.getElementById("test1");
t2 = document.getElementById("test2");
t1.onclick = verandertekst;
t2.onclick = verandertekst;
function verandertekst(){
this.innerHTML = "Tekst is aangepast.";
}
-->
</script>
In de volgende toepassing zorgen we ervoor dat de achtergrondkleur van elk h5-element wordt veranderd wanneer de gebruiker er met de muis over beweegt. De eerste toepassing maakt nog geen gebruik van anonieme functies.
We maken hiervoor gebruik van de getElementsByTagName-methode. Deze methode retourneert een Array van alle objecten met een aangegeven tagnaam. Met een lus kunnen we nu eventhandlers voor alle elementen in deze Array installeren.
In feite passen we hier een CSS-eigenschap van deze tag aan: veel meer hierover in de cursus DHTML.
<h5>Eerste hoofding</h5> <h5>Tweede hoofding</h5> <script type="text/javascript"> <!-- if (document.getElementsByTagName) var x = document.getElementsByTagName('h5'); else if (document.all) var x = document.all.tags('h5'); if(x){ for (var i=0;i<x.length;i++) { x[i].onmouseover = over; x[i].onmouseout = out; } } function over() { this.style.backgroundColor='#FFCC33' } function out() { this.style.backgroundColor='#ffffff' } --> </script>
Aangezien de functies over en out zo eenvoudig zijn is het eleganter hiervoor anonieme functies te gebruiken.
We herwerken het voorbeeld voor h6-elementen, met anonieme functies:
<h6>Eerste hoofding niveau 6</h6>
<h6>Tweede hoofding niveau 6</h6>
<script type="text/javascript">
<!--
if (document.getElementsByTagName)
var x = document.getElementsByTagName('h6');
else if (document.all)
var x = document.all.tags('h6');
if(x){
for (var i=0;i<x.length;i++){
x[i].onmouseover = function ()
{this.style.backgroundColor='#CCFFCC'}
x[i].onmouseout = function ()
{this.style.backgroundColor='#ffffff'}
}
}
-->
</script>
Een anonieme functie wordt gekenmerkt door het sleutelwoord function onmiddellijk gevolgd door een paar ronde haken en de functieopvulling tussen accolades. De functie heeft geen naam en is dus anoniem.
Er rijzen problemen wanneer je twee functionaliteiten wenst te voorzien voor een eventhandler. Je kan natuurlijk alle functionaliteit die je wenst in een functie stoppen en die registreren bij de event-handler.
Programmeren verloopt echter een stuk gestructureerder en onderhoudsvriendeljiker wanneer je voor een functie slechts 1 taak voorziet.
Stel dat een gebruiker ergens kan klikken om een animatie te starten, maar hiervoor moeten eerst een reeks getallen worden gesorteerd. Je zou nu misschien geneigd zijn hetvolgende te doen (op voorwaarde dat de functies sorteerGetallen en startAnimatie bestaan):
element.onclick = sorteerGetallen; element.onclick = startAnimatie;
Deze code levert geen fout op, maar de tweede registratie overschrijft echter de eerste, waardoor de getallen niet zullen worden gesorteerd.
Een mogelijke oplossing hiervoor is een functie te registreren die beide functie aanroept:
element.onclick = function () {sorteerGetallen();startAnimatie()}
De W3C aanbeveling stelt dat we een event-handler kunnen installeren met de methode addEventListener. Deze methode heeft drie argumenten:
In een afhandelingsfunctie refereert this naar het bronobject van de actie.
EventListeners verwijderen doe je met removeEventListener, met dezelfde argumenten als addEventListener.
Microsoft ondersteund de methode attachEvent
Deze methode ontvangt twee argumenten:
Events worden uitgevoerd met bubbling (zie verderop)
Het sleutelwoord this in een afhandelingsfunctie verwijst steeds naar het object window, en is dus niet bruikbaar.
Een functie loskoppelen doe je met de methode detachEvent, met dezelfde argumenten als attachEvent.
Een algemeen probleem rijst bij het koppelen van meerder functies aan een event-handler: je weet niet welke routine eerst zal worden uitgevoerd.
<div class="actie">
<div id="divgeav">Testdivisie</div>
</div>
<script type="text/javascript">
<!--
var d = document.getElementById('divgeav');
//W3C
if(d.addEventListener) {
d.addEventListener('click',toonBericht,false);
d.addEventListener('click',toonNogEenBericht,false);
}
//Microsoft
else if(d.attachEvent){
d.attachEvent('onclick',toonBericht);
d.attachEvent('onclick',toonNogEenBericht);
}
function toonBericht(){
alert('klikken gedetecteerd');
}
function toonNogEenBericht(){
alert('Nog een bericht');
}
-->
</script>
Wanneer je toepassingen maakt heb je vaak toegang nodig tot de eigenschappen van een event. Wanneer je bijvoorbeeld een functie maakt die kan aangeroepen worden vanaf verschillende elementen, dan wil je dikwijls weten welk element de actie heeft veroorzaakt.
Denk maar aan een online winkel, het is interessant te weten als de gebruiker klikt op een knop om een artikel te kopen dat je kan weten welk artikel de klant wenst te kopen :)
De afhandelingsfunctie ontvangt automatisch een argument, dit argument bevat een event-object. Dit object bevat hetgeen we nodig hebben.
Je mag het argument in een variabele stoppen met een naam naar keuze, meestal wordt de naam e gebruikt.
Het object window heeft een eigenschap event die steeds informatie bevat over het laatste event dat heeft plaatsgehad.
Bij W3C-browsers ontvangen we het eventobject als argument in de afhandelingsfuncties, voor Microsoft IE vinden we die informatie in window.event. We zorgen ervoor dat we een variabele e hebben die in beide situaties de event-informatie bevat.
De eigenschap type bevat voor beide browsers het type event (hier click).
<div id="divtoegang1">Testdivisie</div>
<script type="text/javascript">
<!--
var d = document.getElementById('divtoegang1');
//W3C event-handler
if(d.addEventListener) {
d.addEventListener('click',toonBericht,false);
}
//Microsoft event-handler
if(d.attachEvent) {
d.attachEvent('onclick',toonBericht);
}
// argument e ontvangen voor W3C/Netscape
function toonBericht(e){
// e opvullen voor Microsoft IE
if (!e) var e = window.event;
//statements
alert('Event gedetecteerd van het type: ' +e.type);
}
-->
</script>
Dit werkt ook bij traditionele event-handling.
<p id="toegang2">Een alinea om op te klikken</p>
<script type="text/javascript">
<!--
t = document.getElementById('toegang2');
t.onclick = tradKlik;
function tradKlik(e)
{
if(!e) e = window.event;
alert(e.type);
}
-->
</script>
Een alinea om op te klikken
Gebruik je inline event-handlers dan geef je event mee als argument naar de functie. window.event is de correcte eigenschap in het Microsoft model, de andere browsers ondersteunen dit ook in dit speciale geval.
<p onclick="inlineKlik(event)">Een alinea om op te klikken<p> <script type="text/javascript"> <!-- function inlineKlik(e) { alert(e.type); } --> </script>
Een alinea om op te klikken
Nu je weet hoe je toegangkrijgt tot de eigenschappen van een event kan je volgende informatie opvragen:
| Eigenschap | Beschrijving | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| type | Het soort event | ||||||||||||
| target | W3C / Netscape: element waarop het event plaatshad | ||||||||||||
| srcElement | Microsoft: element waarop het event plaatshad | ||||||||||||
| which |
oude eigenschap voor Netscape 4: aangeslagen toets of muisknop
Muisknop:
|
||||||||||||
| keyCode | W3C / Microsoft: aangeslagen toets | ||||||||||||
| button |
Ingedrukte muistoets
|
||||||||||||
| screenX, screenY | Positie van muisaanwijzer t.o.v. het scherm | ||||||||||||
| pageX, pageY | Positie van muisaanwijzer t.o.v. het document | ||||||||||||
| clientX, clientY | Positie van muisaanwijzer t.o.v. het document | ||||||||||||
| relatedTarget | W3C: doelelement bij onmouseout en bronelement bij onmouseover | ||||||||||||
| toElement, fromElement | Microsoft: doelelement bij onmouseout en bronelement bij onmouseover |
In dit voorbeeld zie je twee knoppen die een event-afhandelingsfunctie toonElement delen. Binnen de functie toonElement kunnen we nagaan welke knop werd aangeklikt.
De functie bevat een extra statement om een bug in de browser Safari te omzeilen: als een event plaatsgrijpt op een element dat text bevat wordt de tekstnode gezien als bron in plaats van het element waarin de tekst vervat is.
Het nodeType van een tekstnode is 3.Als het target-element van dit type is gebruiken we de parentNode van dit element.
<input id="knop1" type="button" value="Knop1"><br><br>
<input id="knop2" type="button" value="Knop2">
<script type="text/javascript">
<!--
var k1 = document.getElementById('knop1');
var k2 = document.getElementById('knop2');
//W3C event-handler
if(k1.addEventListener) {
k1.addEventListener('click',toonElement,false);
k2.addEventListener('click',toonElement,false);
}
//Microsoft event-handler
if(k1.attachEvent) {
k1.attachEvent('onclick',toonElement);
k2.attachEvent('onclick',toonElement);
}
function toonElement(e)
{
var targ;
if (!e) var e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // opvangen Safari bug
targ = targ.parentNode;
alert('U hebt geklikt op: ' +targ.id);
}
-->
</script>
Wil je weten welke toets werd ingedrukt, dan kan dit met de eigenschap keyCode van het object event. Netscape 4 werkt met de eigenschap which.
Deze eigenschap bevat een numerieke waarde (ASCII) voor het teken, deze waarde kan je met de methode fromCharCode van het object String omzetten in een letterteken.
<input id="teksttoets" type="text" value="">
<script type="text/javascript">
<!--
var t = document.getElementById('teksttoets');
//W3C event-handler
if(t.addEventListener) {
t.addEventListener('keypress',toonToets,false);
}
//Microsoft event-handler
if(t.attachEvent) {
t.attachEvent('onkeypress',toonToets);
}
function toonToets(e)
{
var code;
if (!e) var e = window.event;
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which
var character = String.fromCharCode(code);
alert('Karakter was ' + character);
}
-->
</script>
Opgepast, bij bepaalde browsers moet je onderscheid maken tussen keydown en keypress om specifieke toetsen te detecteren.
Meer over bvb. de backspace-toets.
Het indrukken van een muisknop wanneer de muisaanwijzer boven een element staat kan je met de eigenschap button. Netscape 4 gebruikt which.
Gebruik beter mousedown of mouseup in plaats van click.
Gezien de rechtermuisknop in W3C en Microsoft afhandeling button steeds de waarde 2 heeft is het de eenvoudigste knop om op te testen.
Wel nog oppassen voor Netscape 4, daar is de waarde van which 3.
<div id="divmuis" style="width:100px;height:50px;border:solid 1px;
background:#CCFFCC;padding:10px">Klik me</div>
<script type="text/javascript">
<!--
var m = document.getElementById('divmuis');
//W3C event-handler
if(m.addEventListener) {
m.addEventListener('mousedown',toonMuisKnop,false);
}
//Microsoft event-handler
if(m.attachEvent) {
m.attachEvent('onmousedown',toonMuisKnop);
}
function toonMuisKnop(e)
{
var rk;
if (!e) var e = window.event;
// rk wordt true als de rechtermuisknop wordt ingedrukt
// anders wordt rk false
if (e.which) rk = (e.which == 3);
else if (e.button) rk = (e.button == 2);
alert('Rechts geklikt ? \n\n' + (rk ? "ja" : "nee"));
}
-->
</script>
Het bepalen van de positie van de muisaanwijzer ten opzichte van de linkerbovenhoek van het scherm:
<HTML>
<HEAD>
<TITLE>Cursus HTML - IVO Brugge</TITLE>
</HEAD>
<BODY>
<h2>Klik ergens op het document</h2>
<script type="text/javascript">
<!--
//W3C event-handler
if(document.addEventListener) {
document.addEventListener('mousedown',toonMuisPositie,false);
}
//Microsoft event-handler
if(document.attachEvent) {
document.attachEvent('onmousedown',toonMuisPositie);
}
function toonMuisPositie(e)
{
if (!e) var e = window.event;
alert("X: " +e.screenX +"\n\nY: " +e.screenY);
}
-->
</script>
</body>
</html>
Om de positie te bepalen ten opzichte van het document heb je pageX, pageY, clientX, clientY en eventueel de srollLeft en scrollTop - eigenschappen van BODY.
Stel dat je binnen het ene element een ander element onderbrengt. Beide elementen hebben een click-event. Welk event wordt dan uitgevoerd? Of allebei? En in welke volgorde?
Bubbling is de term die wordt gebruikt wanneer events afgehandeld worden van binnen naar buiten.
Dit model wordt gebruikt door Microsoft.
Bij capturing worden de events afgehandeld van buiten naar binnen.
Dit model wordt gebruikt door Netscape.
Voor browsers die de W3C-eventregistratie ondersteunen kan je als derde argument meegeven of er bubbling (false) of capturing (true) moet worden gebruikt.
element1.addEventListener('click',doIets,true);
element2.addEventListener('click',doIets2,false);
Dit is enkel van belang als je overkoepelende elementen hebt met een zelfde event-handler.
Gebruik je het traditionele model:
element1.onclick = doIets;
Dan wordt event-bubbling gebruikt
We maken een document met twee divisies die binnen elkaar gelegen zijn, we registreren het click-event voor beide divisies en voor het document.
De functie klik wordt aan de drie event-handlers gekoppeld. Wanneer we op de binnenste divisie klikken zien we drie berichtvensters verschijnen: we klikken op de binnenste maar ook op de buitenste divisie, we klikken ook op het document.
<HTML>
<HEAD>
<TITLE>Cursus HTML - IVO Brugge</TITLE>
</HEAD>
<BODY>
<h2>Klik</h2>
<div id="kopdiv" style="width:200px;height:200px;padding:50px;
background:#FFFF99;border:solid 1px">
<div id="subdiv" style="width:100px;height:100px;padding:50px;
background:#CCFFCC;border:solid 1px">
</div>
</div>
<script type="text/javascript">
document.id = "Hetdocument" // voor currentTarget.id
k = document.getElementById('kopdiv');
s = document.getElementById('subdiv');
<!--
//W3C event-handler
if(document.addEventListener) {
document.addEventListener('click',klik,false);
k.addEventListener('click',klik,false);
s.addEventListener('click',klik,false);
}
//Microsoft event-handler
if(document.attachEvent) {
document.attachEvent('onclick',klik);
k.attachEvent('onclick',klik);
s.attachEvent('onclick',klik);
}
function klik(e)
{
if (!e) var e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // opvangen Safari bug
targ = targ.parentNode;
alert('U hebt geklikt op: '
+(e.currentTarget ? e.currentTarget.id : targ.id));
}
-->
</script>
</body>
</html>
De eigenschap currentTarget werkt niet bij Microsoft, deze eigenschap is nochtans bijzonder interessant daar deze een referentie retourneert naar het element waarvoor de klikactie nu wordt afgehandelt.
De eigenschap srcElement voor Microsoft bevat steeds een verwijzing naar het binnenste element.
Ik geef document hier een id doordat ik voor browsers die currentTarget wel ondersteunen het id van het element toon.
Bij W3C browsers kan je bubbling onderdrukken met:
e.stopPropagation()
Voor Microsoft-browsers gebruik je:
window.event.cancelBubble = true
Cross-browser code:
function doIets(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}
Je hebt zopas geleerd hoe je kan detecteren met welke muisknop een element werd aangekikt.
Wanneer de gebruiker de muis gebruikt kan deze echter heel wat verschillende acties uitvoeren.
Wanneer de gebruiker klikt op een element worden in feite drie events uitgevoerd:
On klik-event wordt dus pas geraised wanneer de gebruiker de muis indrukt boven een element en de muis loslaat boven hetzelfde element.
Wees bewust van het feit dat wanneer je deze drie event-handlers koppelt aan een element ze alle drie worden uitgevoerd als de gebruiker klikt.
Deze actie valt uiteen in volgende events
Het is te vermijden een dblclick en click event op hetzelfde element te definiëren.
mousemove vangt muisbewegingen boven een element op. Wees op je hoede wanneer je dit event voorziet van code, elke beweging van 1 pixel boven het element resulteert in het uitvoeren van de code.
Met mouseover kan je detecteren of de muisaanwijzer boven een element komt, onmouseout onderschept het verlaten van een element.
Door event-bubbling kunnen meerdere events ineens afgevuurd worden.
Het W3C voegt de eigenschap relatedTarget toe aan het event, deze eigenschap bevat een referentie naar:
Microsoft heeft daarvoor de twee eigenschappen fromElement en toElement
Microsoft heeft voor muisbeweging mouseover en mouseout ook twee events beschikbaar die niet 'bubblen' (geen events afvuren van overkoepelende elementen): mouseenter en mouseleave.
| Meer tutorials: |
| leer ook: | html | | xhtml | | css | | asp | | asp.net | | c# | | ado.net | | linq | | ajax | | java | | javascript |