Eventhandtering
Eksempel 1
Vi vet at vi kan plante metoder for å handtere begivenheter direkte i html-elementer slik:
<img onclick="alert(this.alt)" src="bilder/bs1.png" alt="bs1"/>
og vi får dette, klikk på bildet:
![bs1](bilder/bs1.png)
Vi skal forsøke og gjøre dette litt mer generelt ved å plante metodene fra et javaskript som kjøres når siden lastes. Vi identifiserer de elementene som skal ha en metode ved en klasse (class). I eksempelet nedenfor vi vi at alle bilder med class=bilde skal preseneter seg ved et klikk. På denne måte oppnår en lang mer fleksibel arbeidsmetode og det er mindre koding (og omkoding) dersom vi skal redigere større HTML-strukturer. Alt vi trenger å gjøre er å merke alle elementer som skal ha samme dynamiske egenskaper med samme klasse. Klikk på et av bildene under.
![bs1](bilder/bs1.png)
![bs2](bilder/bs2.png)
![bs3](bilder/bs3.png)
![bs4](bilder/bs4.png)
javaskriptet som kjører er slik:
function initCopy1() { bilder=document.getElementsByTagName('img'); for(var ix=0;ix<bilder.length;ix++) if(bilder[ix].className=='bilde') bilder[ix].onclick=showCopyRight1; } function showCopyRight1(e) { if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; alert(e.type+ ' on '+ elt.nodeName+ ' named: ' +elt.alt); }
og htmlkoden er slik:
<img class="bilde" src="bilder/bs1.png" alt="bs1"/> <img class="bilde" src="bilder/bs2.png" alt="bs2"/> <img class="bilde" src="bilder/bs3.png" alt="bs3"/> <img class="bilde" src="bilder/bs4.png" alt="bs4"/> <script type="text/javascript">initCopy1();</script>
Vanligvis forbinder vi class-attributten med kopling mot CSS. Når vi bruker class-attributten til å identifisere de elementene som skal behandles kan man forestille seg at det kan bli en konflikt mellom dette og et eventuelt ønske om å definere en CSS class. Dette problemet løses ved å bruke to class angivelser, adskilt med en blank. En modifisert versjon av eksempelet som tar høyde for dette er slik:
![bs1](bilder/bs1.png)
![bs2](bilder/bs2.png)
![bs3](bilder/bs3.png)
![bs4](bilder/bs4.png)
javaskriptet som kjører er nå slik:
function initCopy2() { bilder=document.getElementsByTagName('*'); for(var ix=0;ix<bilder.length;ix++) if(bilder[ix].className.indexOf('bilde2')!=-1) bilder[ix].onclick=showCopyRight2; } function showCopyRight2(e) { if(!e) e=window.event; if(e.target) elt=e.target; else //IE elt=e.srcElement; alert('Bilde: ' +elt.alt+' copyright bs'); }
og htmlkoden er slik:
<div> <img class="bilde2" src="bilder/bs1.png" alt="bs1"/> <img class="hilited bilde2" src="bilder/bs2.png" alt="bs2"/> <img class="bilde2" src="bilder/bs3.png" alt="bs3"/> <img class="bilde2 hilited" src="bilder/bs4.png" alt="bs4"/> </div> <script type="text/javascript">initCopy2();</script>
Og vi har definert følgende style:
.hilited{border-style:solid;border-color:red;border-width:thin}
Eksempel 2
Vi redesigner litt og introduserer et par standard funksjoner for å plante metoder, fra Quirksmode [3] . Dra musa over et av bildene.
![bs1](bilder/bs1.png)
![bs2](bilder/bs2.png)
![bs3](bilder/bs3.png)
![bs4](bilder/bs4.png)
javaskriptet som kjører er nå slik:
// two methods from: http://www.quirksmode.org/ function addEventSimple(obj,evt,fn) { if (obj.addEventListener) obj.addEventListener(evt,fn,false); else if (obj.attachEvent) obj.attachEvent('on'+evt,fn); } function removeEventSimple(obj,evt,fn) { if (obj.removeEventListener) obj.removeEventListener(evt,fn,false); else if (obj.detachEvent) obj.detachEvent('on'+evt,fn); } function initCopy3(){ bilder=document.getElementsByTagName('img'); for(var ix=0;ix<bilder.length;ix++) if(bilder[ix].className=='bilde3') addEventSimple(bilder[ix],'mouseover',showCopyRight3); } function showCopyRight3(e){ if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; // prepare what to show var newelt=document.createElement('span'); var newtext=document.createTextNode('Copyright: BS'); newelt.style.color='red'; newelt.appendChild(newtext); elt.parentNode.appendChild(newelt); // add remover on mouseiut addEventSimple(elt.parentNode,'mouseout',removeCopyRight3); } function removeCopyRight3(e) { if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; removeEventSimple(elt.parentNode,'mouseout',removeCopyRight3); while(elt.nextSibling) // blank text node(s) ? elt.parentNode.removeChild(elt.nextSibling); }
og htmlkoden er slik:
<div> <div><img class="bilde3" src="bilder/bs1.png" alt="bs1"/></div> <div><img class="bilde3" src="bilder/bs2.png" alt="bs2"/></div> <div><img class="bilde3" src="bilder/bs3.png" alt="bs3"/></div> <div><img class="bilde3" src="bilder/bs4.png" alt="bs4"/></div> </div> <script type="text/javascript">initCopy3();</script>
Bubbling
Nå er det slik at begivenheter "bobler". Det vil si at dersom de ikke blir plukket opp i et element forplanter de seg til omgivende elementer. Det er endog slik at dersom de plukkes opp fortsetter de å vandre utover i strukturen dersom vi ikke stopper dem. Når vi som i eksemplene ovenfor har sett at vi kan plukke opp både begivenhetsstype og opprinnelseselement, må vi kunne plassere metoden som handterer begivenheten andre steder enn i det element der begivenheten skjer.
Vi redesigner eksempel2 slik at vi handterer klikk i et div element som omgir bildene.
![bs1](bilder/bs1.png)
![bs2](bilder/bs2.png)
![bs3](bilder/bs3.png)
![bs4](bilder/bs4.png)
javaskriptet som kjører er nå slik:
// two methods from: http://www.quirksmode.org/ function addEventSimple(obj,evt,fn) { if (obj.addEventListener) obj.addEventListener(evt,fn,false); else if (obj.attachEvent) obj.attachEvent('on'+evt,fn); } function removeEventSimple(obj,evt,fn) { if (obj.removeEventListener) obj.removeEventListener(evt,fn,false); else if (obj.detachEvent) obj.detachEvent('on'+evt,fn); } function initCopy4(){ bilder=document.getElementsByTagName('img'); for(var ix=0;ix<bilder.length;ix++) if(bilder[ix].className=='bilde4') addEventSimple(bilder[ix],'mouseover',showCopyRight4); addEventSimple(document.getElementById('wrapper'),'click',showImageClick); } function showImageClick(e){ if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; alert(e.type+ ' on '+ elt.nodeName+ ' named: ' +elt.alt); } function showCopyRight4(e){ if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; // prepare what to show var newelt=document.createElement('span'); var newtext=document.createTextNode('Copyright: BS'); newelt.style.color='red'; newelt.appendChild(newtext); elt.parentNode.appendChild(newelt); // add remover on mouseout addEventSimple(elt,'mouseout',removeCopyRight4); } function removeCopyRight4(e) { if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; removeEventSimple(elt,'mouseout',removeCopyRight3); while(elt.nextSibling) // blank text node(s) ? elt.parentNode.removeChild(elt.nextSibling); }
og htmlkoden er slik:
<div id="wrapper"> <div><img class="bilde4" src="bilder/bs1.png" alt="bs1"/></div> <div><img class="bilde4" src="bilder/bs2.png" alt="bs2"/></div> <div><img class="bilde4" src="bilder/bs3.png" alt="bs3"/></div> <div><img class="bilde4" src="bilder/bs4.png" alt="bs4"/></div> </div> <script type="text/javascript">initCopy4();</script>
Siden begivenhetene bobler, kunne vi like godt ha plantet klikk-handleren i body-elementet. Problemet med det ville være at vi ville plukke opp alle klikk i hele vevsiden, ikke bare i bildene. Dersom vi hadde plassert en click event handler både i diven som omgir bildene og i body-elementet ville vi fått begivenheten til behandling 2 ganger.
Det er mulig å stoppe forplantingen av begivenheter når vi anser oss ferdige med dem. Vi kan legge inn følgende kodelinjer i en metode for å avbryte boblingen av event e:
... e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); ...
Vi kan illustrere bobling ved å legge inn en clik-handler både i hvert enkelt bilde og i det omgivende div-elementet.
![bs1](bilder/bs1.png)
![bs2](bilder/bs2.png)
![bs3](bilder/bs3.png)
javaskriptet som kjører er nå slik:
function initCopy5(){ bilder=document.getElementsByTagName('img'); for(var ix=0;ix<bilder.length;ix++) if(bilder[ix].className=='bilde5') { bilder[ix].onmouseover=showCopyRight5; bilder[ix].onclick=showImageClick; } document.getElementById('wrapper5').onclick=showImageClick; } function showImageClick(e){ if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; alert(e.type+ ' on '+ elt.nodeName+ ' named: ' +elt.alt); // this will kill bubbling: /* e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); */ } function showCopyRight5(e){ if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; // prepare what to show var newelt=document.createElement('span'); var newtext=document.createTextNode('Copyright: BS'); newelt.style.color='red'; newelt.appendChild(newtext); elt.parentNode.appendChild(newelt); // add remover on mouseout elt.onmouseout=removeCopyRight4; } function removeCopyRight5(e) { if(!e) e=window.event; if(e.target) var elt=e.target; else //IE var elt=e.srcElement; elt.onmouseout=null; while(elt.nextSibling) // blank text node(s) ? elt.parentNode.removeChild(elt.nextSibling); }
og htmlkoden er slik:
<div id="wrapper5"> <div><img class="bilde5" src="bilder/bs1.png" alt="bs1"/></div> <div><img class="bilde5" src="bilder/bs2.png" alt="bs2"/></div> <div><img class="bilde5" src="bilder/bs3.png" alt="bs3"/></div> <div>Du kan også klikke her</div> </div> <script type="text/javascript">initCopy5();</script>