JavaScript
Børre Stenseth

Eventhandtering

Hva

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 respondere på dem.

Ulike typer HTML-elementer kan gi opphav til ulike typer begivenheter. Du vil finne en oversikt hos blandt andre W3C [1] og [2]

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

Du vil finne litt om (finger)touch events i materialet om Responsive Design

I flere av eksemplene nedenfor bruker vi følgende CSS:

.hilited{border-style:solid;border-color:red;border-width:thin}
.container{
	display:  flex;
	display: -webkit-flex;
	flex-flow: row;
	-webkit-flex-flow: row;
	justify-content: space-around;
	-webkit-justify-content: space-around;
	min-height: 50px;
	margin-top:30px;
	max-width:500px
}

Eksempel1

Vi vet at vi kan plante metoder for å handtere begivenheter direkte i html-elementer slik:

<img onclick="this.classList.toggle('hilited')" src="bilder/bs1.png" alt="bs1"/>

og vi får dette, klikk på bildet:

bs1

Eksempel2

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=bilde2 skal hilites. 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, class. Klikk på et av bildene under.

bs1 bs2
    
<img class="bilde2" src="bilder/bs1.png" alt="bs1"/>
<img class="bilde2" src="bilder/bs2.png" alt="bs2"/>

javaskriptet er slik:

_events2.js

Vi kan selvsagt identifisere de elementene vi vil plante events i på mange andre måter, f.eks querySelectorAll().

Eksempel3

Vi redesigner litt og introduserer et par standard funksjoner for å plante metoder.

addEventListener('eventname', myfunction ,false)

Den siste parameteren gir oss anledning til bestemme når vi skal plukke opp begivenheten, enten når den er på vei nedover i blokkstrukturen (true) eller når den "bobler" opp (false). Det siste er default.

Vi bruker her den teknikken at vi planter en funsjon som skal reagere på mouseover. Denne metoden tar i sin tur og planter en motode for mouseout. Dra musa over et av bildene.

bs1
bs2
<div>
<div><img class="bilde3" src="bilder/bs1.png" alt="bs1"/></div>
<div><img class="bilde3" src="bilder/bs2.png" alt="bs2"/></div>
</div>

javaskriptet som kjører er nå slik:

_events3.js

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.

bs3
bs4
bs4
<div id="container4" class="container">
    <div id="box1" class="box">
    <img class="bilde4" src="bilder/bs3.png" alt="bs3"/>
    </div>
    <div id="box2"  class="box">
    <img class="bilde4" src="bilder/bs4.png" alt="bs4"/>
    </div>
    <div id="box3"  class="box">
    <img class="bilde4" src="bilder/bs1.png" alt="bs4"/>
    </div>
</div>

javaskriptet som kjører er nå slik:

function initCopy4(){
    document.getElementById('container4')
        .addEventListener('click',showClick,true);
}
function showClick(e){
    var elt=e.target;
    if(elt.nodeName.toLowerCase()=="img")
        elt.classList.toggle("hilited");
} 

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 div-elementet 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.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
Ingen
<div class="container" id="wrapper5">
<img class="bilde5" src="bilder/bs1.png" alt="bs1"/>
<img class="bilde5" src="bilder/bs2.png" alt="bs2"/>
<img class="bilde5" src="bilder/bs3.png" alt="bs3"/>
</div>
<div id="filename">Ingen</div>

javaskriptet som kjører er nå slik:

_events5.js

Egne events

Vi kan også lage våre egne events, og vi kan gi event-objektet egenskaper. I dette eksempelet definerer vi event kick og vi definerer egenskapen reaction.

bs
bs2
bs10

<div class="container" id="wrapper6">
    <div id="bs1" class="box">
    <img src="bilder/bs1.png" alt="bs"/>
    </div>
    <div id="bs2"  class="box">
    <img src="bilder/bs2.png" alt="bs2"/>
    </div>
    <div id="bs3"  class="box">
    <img src="bilder/bs3.png" alt="bs10"/>
    </div>
</div>
<hr/>
<button onclick="doKick('bs1')" >kick box1</button>
<button onclick="doKick('bs2')" >kick box2</button>
<button onclick="doKick('bs3')" >kick box3</button>

javaskriptet som kjører er nå slik:

_events6.js
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