Lær å gjøre nettsider interaktive med klikk, tastatur og skjemahendelser.
Hendelseshåndtering og brukerinteraksjon
I forrige kapittel lærte vi å endre nettsiden med JavaScript. Men endringene skjedde bare når koden kjørte ved sidelasting. For å skape virkelig interaktive nettsider trenger vi å reagere på brukerens handlinger – klikk, tastettrykk, musebevegelser og skjemainnsending. Dette kalles hendelseshåndtering (event handling).
Hendelsessystemet i JavaScript fungerer etter et enkelt prinsipp: du forteller nettleseren «når denne hendelsen skjer på dette elementet, kjør denne koden». Nettleseren venter tålmodig og kjører koden din bare når hendelsen faktisk inntreffer. Dette er en asynkron programmeringsmodell – koden kjører ikke i rekkefølge fra topp til bunn, men som respons på hendelser.
En hendelse er en handling eller forekomst som skjer i nettleseren og som JavaScript kan reagere på. Eksempler er museklikk (click), tastettrykk (keydown), musebevegelse (mouseover), siderulling (scroll), lasting av siden (load) og innsending av skjema (submit). Hendelser er grunnlaget for all brukerinteraksjon på webben.
Den anbefalte måten å håndtere hendelser på er med addEventListener():
const knapp = document.querySelector("#minKnapp");
knapp.addEventListener("click", function () {
console.log("Knappen ble klikket!");
});addEventListener tar to argumenter:
1. Hendelsesnavnet som en streng (f.eks. "click")
2. En funksjon som kjøres når hendelsen inntreffer (kalles en callback-funksjon)
Du kan også bruke pilfunksjoner:
knapp.addEventListener("click", () => {
console.log("Klikk registrert!");
});Eller referere til en navngitt funksjon:
function handterKlikk() {
console.log("Funksjon ble kalt!");
}
knapp.addEventListener("click", handterKlikk);Vanlige hendelsestyper
| Hendelse | Beskrivelse |
|---|---|
click | Museklikk på elementet |
dblclick | Dobbeltklikk |
mouseover | Musen beveges over elementet |
mouseout | Musen forlater elementet |
keydown | En tast trykkes ned |
keyup | En tast slippes |
input | Verdien i et inputfelt endres |
submit | Et skjema sendes inn |
change | Et skjemaelement endrer verdi |
scroll | Siden eller et element rulles |
load | Siden eller en ressurs er ferdig lastet |
Når en hendelse inntreffer, sender nettleseren automatisk et event-objekt til callback-funksjonen. Dette objektet inneholder nyttig informasjon om hendelsen:
const knapp = document.querySelector("#minKnapp");
knapp.addEventListener("click", function (event) {
console.log("Type:", event.type); // "click"
console.log("Mål:", event.target); // Elementet som ble klikket
console.log("X-posisjon:", event.clientX); // Musens x-koordinat
console.log("Y-posisjon:", event.clientY); // Musens y-koordinat
});Event-objektet for tastehendelser
document.addEventListener("keydown", function (event) {
console.log("Tast:", event.key); // F.eks. "Enter", "a", "Escape"
console.log("Kode:", event.code); // F.eks. "Enter", "KeyA", "Escape"
console.log("Shift holdt:", event.shiftKey); // true/false
console.log("Ctrl holdt:", event.ctrlKey); // true/false
});event.target – identifiser kilde-elementet
event.target refererer til det elementet som faktisk utløste hendelsen. Dette er spesielt nyttig når du har mange like elementer:
const knapper = document.querySelectorAll(".farge-knapp");
knapper.forEach(knapp => {
knapp.addEventListener("click", function (event) {
const valgtFarge = event.target.dataset.farge;
document.body.style.backgroundColor = valgtFarge;
});
});Med tilhørende HTML:
<button class="farge-knapp" data-farge="lightblue">Blå</button>
<button class="farge-knapp" data-farge="lightgreen">Grønn</button>
<button class="farge-knapp" data-farge="lightyellow">Gul</button>En av de viktigste bruksområdene for hendelseshåndtering er skjemavalidering – å sjekke at brukeren har fylt inn gyldige data før de sendes til serveren.
Forhindre standard oppførsel
Når et skjema sendes inn, laster nettleseren normalt siden på nytt. For å håndtere innsendingen med JavaScript må vi stoppe denne oppførselen:
const skjema = document.querySelector("#registrering");
skjema.addEventListener("submit", function (event) {
event.preventDefault(); // Stopp sidelasting!
// Hent verdier fra skjemaet
const navn = document.querySelector("#navn").value;
const epost = document.querySelector("#epost").value;
console.log("Navn:", navn);
console.log("E-post:", epost);
});Komplett skjemavalidering
<form id="pamelding">
<label>Navn: <input type="text" id="navn"></label>
<label>E-post: <input type="email" id="epost"></label>
<label>Alder: <input type="number" id="alder"></label>
<button type="submit">Send inn</button>
<div id="feilmeldinger"></div>
</form>const skjema = document.querySelector("#pamelding");
skjema.addEventListener("submit", function (event) {
event.preventDefault();
const navn = document.querySelector("#navn").value.trim();
const epost = document.querySelector("#epost").value.trim();
const alder = Number(document.querySelector("#alder").value);
const feilDiv = document.querySelector("#feilmeldinger");
const feil = [];
// Valider navn
if (navn === "") {
feil.push("Navn er obligatorisk.");
} else if (navn.length < 2) {
feil.push("Navnet må ha minst 2 tegn.");
}
// Valider e-post (enkel sjekk)
if (!epost.includes("@") || !epost.includes(".")) {
feil.push("Ugyldig e-postadresse.");
}
// Valider alder
if (isNaN(alder) || alder < 13 || alder > 120) {
feil.push("Alder må være mellom 13 og 120.");
}
// Vis resultat
if (feil.length > 0) {
feilDiv.innerHTML = feil.map(f => "<p style='color:red'>" + f + "</p>").join("");
} else {
feilDiv.innerHTML = "<p style='color:green'>Påmelding mottatt!</p>";
}
});Når du har mange elementer som skal reagere på klikk (for eksempel en liste med hundre elementer), er det ineffektivt å legge til en hendelseslytter på hvert enkelt element. I stedet kan du bruke event delegation – én lytter på forelder-elementet:
// I stedet for dette (ineffektivt):
document.querySelectorAll("li").forEach(li => {
li.addEventListener("click", function () {
console.log(this.textContent);
});
});
// Bruk event delegation (effektivt):
document.querySelector("ul").addEventListener("click", function (event) {
if (event.target.tagName === "LI") {
console.log(event.target.textContent);
}
});Hendelsen bobler opp (event bubbling) fra barneelementet til forelderen. Lytteren på <ul> fanger opp klikk på alle <li>-elementer, og event.target forteller oss hvilket element som ble klikket.
Event delegation har to store fordeler:
1. Ytelse: Bare én lytter i stedet for mange
2. Dynamisk innhold: Fungerer også for elementer som legges til senere med JavaScript
Her er et eksempel som kombinerer hendelseshåndtering og DOM-manipulering til en liten quiz:
<div id="quiz">
<h2>Quiz: JavaScript</h2>
<p id="sporsmal">Hva brukes JavaScript til?</p>
<div id="alternativer">
<button class="alt" data-korrekt="false">Å strukturere nettsider</button>
<button class="alt" data-korrekt="true">Å gjøre nettsider interaktive</button>
<button class="alt" data-korrekt="false">Å style nettsider</button>
</div>
<p id="resultat"></p>
</div>const alternativer = document.querySelector("#alternativer");
const resultat = document.querySelector("#resultat");
alternativer.addEventListener("click", function (event) {
// Sjekk at et alternativ-knapp ble klikket
if (!event.target.classList.contains("alt")) {
return;
}
const erKorrekt = event.target.dataset.korrekt === "true";
// Deaktiver alle knapper
document.querySelectorAll(".alt").forEach(knapp => {
knapp.disabled = true;
if (knapp.dataset.korrekt === "true") {
knapp.style.backgroundColor = "lightgreen";
}
});
// Vis tilbakemelding
if (erKorrekt) {
resultat.textContent = "Riktig! JavaScript gjør nettsider interaktive.";
resultat.style.color = "green";
event.target.style.backgroundColor = "lightgreen";
} else {
resultat.textContent = "Feil! Prøv igjen neste gang.";
resultat.style.color = "red";
event.target.style.backgroundColor = "lightcoral";
}
});Eksempelet bruker event delegation på #alternativer-elementet i stedet for individuelle lyttere på hver knapp. dataset-egenskapen leser data-*-attributter fra HTML, og vi bruker DOM-manipulering for visuell tilbakemelding.
input-hendelsen utløses hver gang brukeren endrer verdien i et tekstfelt – for hvert eneste tastetrykk. Dette gir sanntids-tilbakemelding:const sokefeld = document.querySelector("#sok");
const resultatDiv = document.querySelector("#resultater");
sokefeld.addEventListener("input", function (event) {
const sokeTekst = event.target.value.toLowerCase();
if (sokeTekst.length === 0) {
resultatDiv.textContent = "";
return;
}
// Enkel filtrering av en liste
const elementer = ["JavaScript", "HTML", "CSS", "Python", "Java"];
const treff = elementer.filter(e => e.toLowerCase().includes(sokeTekst));
resultatDiv.textContent = treff.length > 0
? "Treff: " + treff.join(", ")
: "Ingen treff.";
});Dette mønsteret brukes for sanntidssøk, passordstyrke-indikatorer, tegngrenser og lignende funksjoner.
Hvilken metode brukes for å lytte etter hendelser i JavaScript?
Hva gjør event.preventDefault()?
Hva er event.target i denne koden?
document.querySelector("ul").addEventListener("click", function(event) {
console.log(event.target);
});Når brukeren klikker på et <li>-element inne i listen.
Hva er fordelen med event delegation?
Skriv JavaScript-kode for en knapp med id="morsknapp". Når knappen klikkes for første gang, skal teksten i et <p>-element med id="morsmelding" endres til "Du er fantastisk!". Ved neste klikk skal teksten endres til "Og det vet du!". Knappen skal veksle mellom disse to meldingene.
Lag en komplett skjemavalidering med JavaScript. Skjemaet har feltene "brukernavn" (minst 3 tegn), "epost" (må inneholde @ og .), og "passord" (minst 8 tegn). Vis feilmeldinger i et <div> med id="feil". Bruk preventDefault() for å stoppe innsending ved feil.
Hva er forskjellen mellom "input"-hendelsen og "change"-hendelsen på et tekstfelt?
Lag en interaktiv teller med JavaScript. Siden har tre knapper: "+1", "-1" og "Nullstill", og et <span> med id="teller" som viser gjeldende verdi (starter på 0). Telleren skal ikke kunne gå under 0. Bruk én hendelseslytter med event delegation på en felles forelder-container.
Oppsummering
I dette kapittelet har du lært:
- Hendelse (event): en handling i nettleseren JavaScript kan reagere på.
- addEventListener: kobler en funksjon til en hendelse.
- Hendelsestyper: click, keydown, submit m.fl.
- event.target: identifiserer kilde-elementet.
- preventDefault og skjemavalidering: kontrollerer standard oppførsel.
Noekkelbegreper
| Begrep | Forklaring |
|---|---|
| Hendelse | Handling i nettleseren JavaScript kan reagere på |
| addEventListener | Kobler funksjon til en hendelse |
| event.target | Elementet som utløste hendelsen |
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.