!

Dette materialet blir ikke lenger vedlikeholdt. Du vil finne oppdatert materiale på siden: http://borres.hiof.no/wep/

Javascript
Event
Børre Stenseth
JavaScript > Omgivelsene >Begivenheter

Eventhandtering

Hva
Handtering av events i Javascript

Javascript skal realisere dynamikken på en vevside. Som regel er dynamikken initiert fra en eller annen brukergenerert begivenhet. Vi må derfor ha mekanismer for å plukke opp slike begivenheter og resondere på dem.

Ulike typer HTML-elementer kan gi opphav til ulike typer begivenheter. Noe av dette er beskrevet i modulen Omgivelsene og du vil finne en oversikt hos W3C [1] og [2]

I denne modulen skal vi konsentrere oss om de begivenhetene vi normalt har mest med å gjøre: Begivenheter initiert av musebevegleser og museklikk.

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

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 bs2 bs3 bs4

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 bs2 bs3 bs4

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
bs2
bs3
bs4

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
bs2
bs3
bs4

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
bs2
bs3
Du kan også klikke her

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>
Referanser
  1. Standard Event Attributes W3C www.w3schools.com/tags/ref_eventattributes.asp 14-10-2010
  1. Document Object Model Events W3C www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html 14-10-2010
  1. Quirksmode Peter-Paul Koch Quirksmode.org www.quirksmode.org/ 14-03-2010
Vedlikehold

B. Stenseth, oktober 2010

( Velkommen ) JavaScript > Omgivelsene >Begivenheter ( Egne Objekter )