Webbutveckling 1 · område 6 · guide
JavaScript: läsa, koppla in, anpassa
Guiden är områdets uppslagsbok. Den ska fungera för den som var borta, och den ska gå att slå i mitt under ett arbetspass. Alla exempel är hämtade ur referensprojekt/ – Vikstadssajten med sex moduler inbyggda – så att koden i guiden och koden i förlagan är samma kod.
Målet i den här kursen är inte att du ska kunna programmera från grunden. Det är att du ska kunna läsa färdig kod, förstå vad den gör, koppla in den och anpassa den. Det är så det mesta av webbutveckling ser ut i verkligheten, och det är det Projekt 5 kräver.
Vad du kan efter guiden
- Säga vad JavaScript gör som HTML och CSS inte kan.
- Läsa en modul rad för rad och förklara vad varje rad gör.
- Känna igen de fem byggstenarna: variabel, funktion, händelse, villkor och lista.
- Koppla in en modul i din egen sajt – rätt fil, rätt plats, rätt sökväg.
- Öppna konsolen, läsa ett felmeddelande och hitta raden det handlar om.
- Ändra en modul utan att ha den sönder: veta vad som är säkert och vad som inte är det.
- Byta klassnamn i en modul så att den passar din HTML.
- Svara på frågan "vad händer om JavaScript inte körs?" för varje modul du byggt in.
1. Vad JavaScript gör
Du kan redan två språk, och de gör var sin sak:
| Språk | Svarar på frågan |
|---|---|
| HTML | Vad är det här? En rubrik, en länk, ett formulärfält |
| CSS | Hur ser det ut? Grönt, 16 pixlar, i en spalt |
| JavaScript | Vad händer när någon gör något? |
Den tredje frågan är den nya. HTML och CSS beskriver en sida som den är. JavaScript låter sidan ändra sig medan besökaren är kvar på den: en meny öppnas, ett filter gömmer hälften av innehållet, ett formulär säger vad som är fel innan det skickas.
Vad det inte gör
JavaScript i den här kursen körs i besökarens webbläsare. Det betyder tre saker:
- Det kan inte spara något på en server. Inga konton, inga databaser, ingen e-post som skickas.
- Besökaren kan stänga av det, och några gör det. Sajten ska fungera ändå – det är hela område 7.
- All kod du skriver är synlig för besökaren. Lägg aldrig något hemligt i den.
Var koden bor
I en egen fil med ändelsen .js, som du kopplar in i HTML:en med en script-tagg. Aldrig inuti HTML-elementen: en sajt där onclick="…" står utspritt i markupen är en sajt där ingen hittar felet. Samma princip som när stilarna flyttade ut ur style-attributen i område 3.
<script src="js/meny.js" defer></script>
Prova själv
Öppna referensprojekt/index.html i webbläsaren, tryck F12 och gå till fliken Console. Skriv document.title och tryck Enter. Webbläsaren svarar med sidans titel. Du har just läst av sidan med JavaScript.
2. De fem byggstenarna
Nästan all kod du kommer att läsa i den här kursen är byggd av fem saker. Kan du känna igen dem kan du läsa en modul.
| Byggsten | Vad den är | Ser ut så här |
|---|---|---|
| Variabel | Ett namn på ett värde | const knapp = … |
| Funktion | Ett namn på några rader kod som ska köras ihop | function oppna() { … } |
| Händelse | Något besökaren gör, och koden som ska svara | knapp.addEventListener("click", …) |
| Villkor | Kör det här bara om något stämmer | if (arOppen) { … } |
| Lista | Flera värden i en, som går att gå igenom | bilder.forEach(…) |
Variabler: const och let
En variabel är ett namn på ett värde, så att du slipper skriva om värdet varje gång.
const KNAPP = ".menyknapp";
let aktuell = 0;
Skillnaden: const betyder att namnet aldrig ska peka på något annat. let betyder att värdet kommer att ändras. I karusell.js är aktuell en let för att den räknar upp när man bläddrar; allt annat är const.
var finns också – använd den inte
Du kommer att se var i äldre kod och i äldre guider på nätet. Den fungerar, men den har regler som överraskar. const som standard, let när värdet ska ändras.
Namnet spelar roll. const KNAPP i versaler betyder "det här är en inställning som inte ändras under körningen" – det är så modulerna märker sin ÄNDRA HÄR-zon. Vanliga variabler skrivs med små bokstäver: knapp, lista, aktuell.
Funktioner
En funktion är några rader kod som fått ett namn, så att de går att köra när man vill och flera gånger.
function stang() {
knapp.setAttribute("aria-expanded", "false");
knapp.textContent = TEXT_STANGD;
}
Raderna körs inte när funktionen skrivs. De körs när någon anropar den, genom att skriva namnet med parenteser: stang(). Parenteserna är det som säger "kör nu".
En funktion kan ta emot värden, som kallas parametrar:
function visa(index) { // index är parametern
aktuell = index;
…
}
visa(0); // anrop med värdet 0
Prova själv
Öppna js/meny.js – i referensprojektet, eller på modulbibliotekets sida där hela koden står. Leta upp en const, en let om det finns någon, och två funktioner. Skriv ner vad varje funktion gör i en mening.
3. Hitta element på sidan
Innan koden kan ändra något på sidan måste den hitta det. Det kallas DOM-selektion – DOM är webbläsarens modell av sidan, och selektion är att välja ut en del av den.
const knapp = document.querySelector(".menyknapp");
document är hela sidan. querySelector letar upp det första elementet som matchar, och det som står inom parentesen är en CSS-selektor – exakt samma sorts selektor som du skriver i stilmallen.
| Vad du vill ha | Så skriver du |
|---|---|
Elementet med class="menyknapp" | document.querySelector(".menyknapp") |
Elementet med id="innehall" | document.querySelector("#innehall") |
Elementet med id="innehall", kortare | document.getElementById("innehall") |
Första button på sidan | document.querySelector("button") |
Alla element med data-grupp | document.querySelectorAll("[data-grupp]") |
Skillnaden mellan de två sista är viktig: querySelector ger ett element, querySelectorAll ger alla som en lista. Ska du göra något med flera element behöver du den senare, och sedan en loop (avsnitt 7).
Hittar den inget?
Då får du null – ordet för "ingenting". Och försöker du använda null kraschar koden med felet Cannot read properties of null. Det är webbens vanligaste felmeddelande, och avsnitt 9 handlar om det.
Därför börjar varje modul i biblioteket med samma sorts rad:
const knapp = document.querySelector(KNAPP);
const lista = document.querySelector(LISTA);
if (!knapp || !lista) { return; }
Läs den högt: "om knappen inte finns, eller listan inte finns – avsluta." Utropstecknet betyder "inte". Två streck || betyder "eller". return avslutar funktionen direkt.
Det är den raden som gör att du kan lägga in meny.js på en sida som saknar meny utan att något går sönder.
Prova själv
Öppna referensprojektets startsida, tryck F12 → Console, och skriv:
document.querySelector(".menyknapp")
Webbläsaren svarar med elementet. Skriv sedan document.querySelector(".finns-inte") – svaret blir null.
4. Ändra sidan
När koden hittat ett element kan den ändra det. Fyra sätt räcker för hela modulbiblioteket.
| Vad du vill ändra | Så skriver du | Exempel ur biblioteket |
|---|---|---|
| Texten i ett element | element.textContent = "…" | knapp.textContent = TEXT_OPPEN; |
| En klass på elementet | element.classList.add("…") | karusell.classList.add("karusell-igang"); |
| Ett attribut | element.setAttribute("namn", "värde") | knapp.setAttribute("aria-expanded", "true"); |
| Göm eller visa | element.hidden = true / false | del.hidden = true; |
textContent, inte innerHTML
Det finns ett annat sätt att sätta text: innerHTML. Det tolkar innehållet som HTML, vilket betyder att text som kommer utifrån – från ett formulär, från en adress – kan innehålla taggar och skript som körs. Det är webbens vanligaste säkerhetshål, och det heter XSS (säkerhetsguiden i område 5, avsnitt 7).
Regeln: är det text, använd textContent. Modulbiblioteket använder innerHTML noll gånger.
classList – fyra metoder
element.classList.add("klar"); // lägg till
element.classList.remove("klar"); // ta bort
element.classList.toggle("klar"); // finns den? ta bort. Annars lägg till
element.classList.contains("klar"); // frågar: finns den? svarar true eller false
toggle kan också ta ett andra värde som säger vad resultatet ska bli:
fraga.classList.toggle("quiz-ratt", arRatt); // sätt klassen om arRatt är true
Det är den raden quiz.js använder för att märka varje fråga som rätt eller fel.
Attribut som betyder något
Tre attribut återkommer i modulerna, och de gör dubbel nytta:
| Attribut | Säger till skärmläsaren | Används av CSS:en |
|---|---|---|
aria-expanded | om menyn är öppen | visar eller gömmer listan |
aria-pressed | om knappen är vald | färgar den valda filterknappen |
aria-invalid | att fältet har ett fel | röd ram runt fältet |
Det här är mönstret hela biblioteket bygger på: skriptet byter ett attribut, stilmallen reagerar på attributet. Ingen modul sätter färger eller storlekar direkt i koden. Det gör att du kan ändra utseendet i CSS:en utan att röra JavaScript.
Prova själv
I konsolen på referensprojektets startsida:
document.querySelector("h1").textContent = "Min rubrik"
Rubriken byts. Ladda om sidan – den är tillbaka. Allt du gör i konsolen gäller bara tills sidan laddas om, vilket gör konsolen ofarlig att experimentera i.
5. Händelser
En händelse är något som sker: ett klick, en tangenttryckning, ett formulär som skickas. Att lyssna på en händelse är att säga "när det här händer, kör den här funktionen".
knapp.addEventListener("click", function () {
// det som ska hända
});
Tre delar: elementet som ska lyssna, vilken händelse, och funktionen som körs. Funktionen har inget namn här – den skrivs direkt på plats, och det är vanligt. Den kan också ha ett namn:
forra.addEventListener("click", bakat);
Här står bakat utan parenteser. Det är med avsikt: du ger funktionen som värde till lyssnaren, du anropar den inte. bakat() med parenteser hade kört funktionen direkt när raden lästes – ett vanligt fel.
De fem händelser du behöver
| Händelse | Sker när | Var i biblioteket |
|---|---|---|
click | någon klickar, eller trycker Enter på en knapp | meny, galleri, karusell, mörkt läge |
keydown | en tangent trycks ner | meny (Escape), karusell (pilar) |
submit | ett formulär skickas | validering, quiz |
input | någon skriver i ett fält | validering |
change | ett fält får ett nytt värde och lämnas | – |
Händelseobjektet
Funktionen får ett värde: själva händelsen. I biblioteket heter den handelse.
document.addEventListener("keydown", function (handelse) {
if (handelse.key === "Escape") { … }
});
handelse.key är vilken tangent det var. handelse.target är elementet händelsen kom från. Och handelse.preventDefault() stoppar det webbläsaren annars hade gjort – det är den som hindrar ett formulär från att skickas:
quiz.addEventListener("submit", function (handelse) {
handelse.preventDefault();
ratta();
});
En lyssnare i stället för många
galleri.js har en enda lyssnare på hela filterraden, inte en per knapp:
filterrad.addEventListener("click", function (handelse) {
const knapp = handelse.target.closest("button");
if (!knapp) { return; }
filtrera(knapp.dataset.valj);
});
Klicket "bubblar" upp från knappen till raden, och closest("button") letar uppåt efter närmaste knapp. Det kallas händelsedelegering, och det behövs här för att knapparna skapas av skriptet – de fanns inte när lyssnaren sattes.
Prova själv
I konsolen, på vilken sida som helst:
document.querySelector("h1").addEventListener("click", function () { alert("Hej"); })
Klicka sedan på rubriken.
6. Villkor
Ett villkor kör kod bara när något stämmer.
if (arOppen) {
stang();
} else {
oppna();
}
Det som står i parentesen ska vara sant eller falskt – true eller false.
Jämförelser
| Skrivs | Betyder |
|---|---|
=== | är exakt lika med |
!== | är inte lika med |
> < >= <= | större än, mindre än, och med "eller lika" |
&& | och – båda måste stämma |
|| | eller – minst en måste stämma |
! | inte – vänder sant till falskt |
Tre likhetstecken, inte två. == finns och gör nästan samma sak, men den jämför slarvigt: "1" == 1 är sant med två tecken och falskt med tre. Använd alltid ===.
Sanning och falskhet
Allt går att använda som villkor, även det som inte är true eller false. Då gäller en enkel regel: tomt är falskt, allt annat är sant.
| Falskt | Sant |
|---|---|
false, 0, "" (tom text), null, undefined | Alla andra värden – även "0" och en tom lista |
Det är därför if (!knapp) { return; } fungerar: hittades ingen knapp är värdet null, alltså falskt, och !null blir sant.
Kortformen som finns i biblioteket
knapp.textContent = arMork ? TEXT_TILL_LJUS : TEXT_TILL_MORK;
Frågetecknet läses som ett if: "är arMork sant? ta det före kolonet. Annars det efter." Den kallas ternär och är praktisk när båda grenarna är korta. Är de långa, skriv ett vanligt if.
7. Listor och loopar
querySelectorAll ger en lista med element. För att göra något med varje element behöver du gå igenom listan.
delar.forEach(function (del) {
del.hidden = true;
});
forEach betyder "för varje". Funktionen körs en gång per element, och del är det element som är i tur. Namnet väljer du själv.
Vill du veta vilket nummer i ordningen elementet har får du det som ett andra värde:
bilder.forEach(function (bild, i) {
bild.hidden = i !== aktuell;
});
i är index, och det börjar på 0. Första bilden är 0, andra är 1. Det är därför karusell.js skriver aktuell + 1 när den visar "Bild 1 av 3" för människor.
Den andra loopen: for
Du ser också den här formen, och quiz.js använder den:
for (let i = 0; i < fragor.length; i++) {
const fraga = fragor[i];
…
}
Tre delar i parentesen: börja på 0 · fortsätt så länge i är mindre än antalet · öka i med ett varje varv. .length är hur många, och fragor[i] är elementet på plats i.
Varför två sorter? forEach är lättare att läsa, men går inte att avbryta i förtid. quiz.js måste kunna avbryta när den hittar en obesvarad fråga, och därför använder den for. Det är hela skillnaden.
Objekt: en lista med namn i stället för nummer
FACIT i quiz.js ser ut så här:
const FACIT = {
f1: "b",
f2: "c",
f3: "a"
};
Det är ett objekt: värden som hämtas med ett namn i stället för ett nummer. FACIT.f1 eller FACIT["f1"] ger "b". Du behöver inte kunna bygga objekt i den här kursen, men du ska känna igen dem – två av modulerna har sitt facit eller sina etiketter i ett.
Prova själv
I konsolen på artsidan:
document.querySelectorAll("[data-grupp]").length
Svaret är hur många sektioner som går att filtrera.
8. Koppla in en modul
Det här avsnittet är lektion 53, och det är de fem stegen du gör varje gång.
1. Lägg filen i js/
Skapa mappen js i ditt repo om den inte finns, och lägg modulens .js-fil där. Filnamnet får du behålla. Gemener, bindestreck, ingen å ä ö i filnamn – samma regler som för bilder och sidor.
2. Lägg in script-taggen
Sist i body, precis före </body>, på varje sida där modulen ska användas:
<script src="js/meny.js" defer></script>
</body>
3. Kontrollera sökvägen
src="js/meny.js" betyder "mappen js, i samma mapp som den här HTML-filen". Ligger sidan i en undermapp blir det ../js/meny.js. Det är samma regler som för <link rel="stylesheet"> och för bilder – och det är fortfarande det vanligaste felet.
4. Lägg in den HTML modulen kräver
Varje modul säger överst i filen exakt vilken HTML den behöver. Den HTML:en måste finnas, annars avslutar modulen tyst (avsnitt 3). Kopiera från modulbibliotekets sida, eller från demosidan i referensprojekt/demo/.
5. Ta med CSS:en
Modulen har ett avsnitt i stil.css – 13a till 13f. Kopiera hela avsnittet, kommentarer och allt, och klistra in sist i din egen stilmall.
Vad defer gör, och varför det måste stå där
Utan defer läser webbläsaren HTML:en uppifrån och ner och stannar när den möter en script-tagg: hämtar filen, kör den, och fortsätter sedan. Ett skript som körs innan sidan är färdigläst hittar inte de element det letar efter.
Med defer hämtas filen parallellt och körs när hela HTML:en finns. Resultatet: sidan laddas snabbare, och skriptet hittar alltid sina element.
| Så här | Vad som händer |
|---|---|
<script src="…"> i head | Kör för tidigt. querySelector ger null |
<script src="…"> sist i body | Fungerar, men blockerar inläsningen |
<script src="…" defer> | Rätt. Hämtas parallellt, körs när HTML:en är klar |
Flera moduler på samma sida
Lägg en script-tagg per modul. Ordningen spelar ingen roll – varje modul är inkapslad och vet ingenting om de andra.
<script src="js/meny.js" defer></script>
<script src="js/morkt-lage.js" defer></script>
<script src="js/galleri.js" defer></script>
Prova själv
Öppna din egen sajt, lägg in meny.js enligt de fem stegen, och ladda om. Fungerar det inte: gå till avsnitt 9 innan du ändrar något i koden.
9. Konsolen
Konsolen är webbläsarens meddelanderuta, och den är ditt viktigaste verktyg i det här området. Öppna den innan du felsöker, inte efter.
F12, eller högerklick → Granska, sedan fliken Console.
Läs felet uppifrån
Ett felmeddelande har tre delar, och alla tre behövs:
Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
at meny.js:48
| Del | Vad den säger |
|---|---|
TypeError | Vilken sorts fel |
Cannot read properties of null | Vad som gick fel |
at meny.js:48 | Vilken fil och vilken rad |
Sista raden är den du ska börja med. Klicka på den – webbläsaren öppnar filen på rätt rad.
De fem fel du kommer att få
| Meddelandet säger | Vad det betyder | Vad du gör |
|---|---|---|
Failed to load resource: 404 | Filen hittades inte | Fel sökväg i src, eller fel filnamn. Kontrollera stavningen, inklusive stora och små bokstäver |
Cannot read properties of null | Skriptet hittade inte elementet | Klassnamnet i koden och i HTML:en stämmer inte. Eller skriptet kördes för tidigt – saknas defer? |
X is not defined | Ett namn som inte finns | Stavfel i ett variabelnamn |
X is not a function | Namnet finns, men är inte en funktion | Stavfel i ett metodnamn: querySelectorAll med litet s, addEventlistener med litet l |
Unexpected token | Koden går inte att läsa | En parentes, klammer eller ett citattecken som saknas. Ofta raden före den som anges |
Filen kördes inte alls
Ser du inget fel men inget händer? Kontrollera att filen verkligen hämtades: fliken Network i samma verktyg, ladda om, och leta efter din .js-fil i listan. Står det 404 där är det steg 3 i förra avsnittet som är fel.
console.log – när du vill veta vad koden gör
console.log("Här är jag", knapp);
Skriv raden där du vill veta om koden kommer fram, och vad ett värde är just då. Utskriften hamnar i konsolen.
Ta bort dem när du är klar. En konsol full av dina egna utskrifter är en konsol där du inte ser felen. Modulbiblioteket innehåller noll console.log.
Prova själv
Öppna referensprojektets startsida, konsolen, och skriv dokument.title (med k). Läs felet. Rätta till document.title.
10. Anpassa en modul
Det här är lektion 54, och det är gränsen som gör hela biblioteket användbart.
Varje modul har en zon överst:
/* ===== ÄNDRA HÄR ====================================================== */
const KNAPP = ".menyknapp";
const LISTA = "#huvudmeny-lista";
const TEXT_STANGD = "Meny";
const TEXT_OPPEN = "Stäng";
/* ===== SLUT PÅ ÄNDRA HÄR – nedanför behöver ingenting ändras ========= */
Allt i zonen är ditt. Allt under är inte det.
Vad du får ändra
| Sort | Exempel | Vad du ska tänka på |
|---|---|---|
| Texter | TEXT_STANGD = "Meny" | Vad som helst. Behåll citattecknen |
| Klassnamn och id | KNAPP = ".menyknapp" | Måste stämma exakt med din HTML. Punkt för klass, brädgård för id |
| Inställningar | BORJA_OM = true | Läs kommentaren bredvid – den säger vad värdena betyder |
| Innehåll i objekt | FACIT, GRUPPNAMN | Lägg till eller ta bort rader. Behåll kommatecknen mellan raderna |
Att byta klassnamn – gör det på två ställen
Vill du att din knapp ska heta .oppna-meny i stället för .menyknapp måste båda ändras:
const KNAPP = ".oppna-meny"; // i modulen
<button type="button" class="oppna-meny" hidden …> <!-- i HTML:en -->
.oppna-meny { … } /* och i CSS:en */
Missar du ett av de tre hittar skriptet ingenting, och du får null i konsolen. Enklare väg: behåll modulens klassnamn och ändra din HTML i stället. Då är det ett ställe mindre att glömma.
Vad du inte ska röra
Allt under zonen. Om du ändå vill – och det gör du i A-spåret – gäller två regler:
- Ändra en sak i taget och ladda om. Går det sönder vet du vad det var.
- Ha originalet kvar. Kopiera filen innan du börjar, eller committa först. Git är till för precis det här.
Kontrollen: fungerar sidan utan modulen?
När du byggt in en modul, gör det här en gång:
- Kommentera bort
script-taggen:<!-- <script src="js/meny.js" defer></script> --> - Ladda om.
- Fungerar sidan? Går menyn att använda, syns innehållet?
Svaret ska vara ja, och orsaken är att det som bara fungerar med skript har hidden i HTML:en. Det här är inte ett krav i Projekt 5 – men det är hela område 7, och det är mycket lättare att bygga rätt från början än att laga i efterhand.
Prova själv
Öppna js/morkt-lage.js – i referensprojektet, eller läs den på modulbibliotekets sida. Byt TEXT_TILL_MORK till något eget, ladda om sidan och se knappens text ändras. Byt sedan NYCKEL och ladda om – ditt sparade val är borta, för modulen letar under ett nytt namn.
11. Läs en hel modul: meny.js
Det här är lektion 52:s moment, och det står här så att du kan göra om det själv. Modulen är 75 rader; nedan är de som gör något, i ordning.
(function () {
"use strict";
Kapseln. Allt inuti är privat för den här filen. Sex moduler på samma sida kan alla ha en variabel som heter knapp utan att krocka. "use strict" gör att ett stavfel i ett variabelnamn blir ett fel i konsolen i stället för att tyst skapa en ny variabel.
const KNAPP = ".menyknapp";
const LISTA = "#huvudmeny-lista";
const TEXT_STANGD = "Meny";
const TEXT_OPPEN = "Stäng";
Inställningarna. Avsnitt 10.
const knapp = document.querySelector(KNAPP);
const lista = document.querySelector(LISTA);
if (!knapp || !lista) { return; }
Hitta elementen, avbryt om de inte finns. Avsnitt 3.
knapp.hidden = false;
knapp.textContent = TEXT_STANGD;
Nu får knappen synas. Den hade hidden i HTML:en. Kommer skriptet hit fungerar det, och då – och bara då – visas knappen. Det är den rad som gör modulen diskret.
function oppna() {
knapp.setAttribute("aria-expanded", "true");
knapp.textContent = TEXT_OPPEN;
}
function stang() {
knapp.setAttribute("aria-expanded", "false");
knapp.textContent = TEXT_STANGD;
}
Två funktioner som gör var sin sak. Lägg märke till att ingen av dem gömmer eller visar listan – de byter bara ett attribut. Det är CSS:en i avsnitt 13a som reagerar.
knapp.addEventListener("click", function () {
const arOppen = knapp.getAttribute("aria-expanded") === "true";
if (arOppen) {
stang();
} else {
oppna();
}
});
Klicket. Läs av attributet, jämför med "true", och gör motsatsen mot det som är. Modulen behöver ingen egen variabel för att minnas om menyn är öppen – attributet är minnet, och det är samma attribut som skärmläsaren läser.
document.addEventListener("keydown", function (handelse) {
if (handelse.key === "Escape" && knapp.getAttribute("aria-expanded") === "true") {
stang();
knapp.focus();
}
});
Escape. Lyssnaren sitter på document, inte på knappen, för tangenttrycket ska fungera var som helst på sidan. && betyder att båda villkoren måste stämma: det ska vara Escape och menyn ska vara öppen. knapp.focus() flyttar fokus tillbaka, så att den som navigerar med tangentbord vet var hen är.
})();
Kapseln stängs och körs. Parenteserna sist är det som startar hela funktionen.
Prova själv
Gör samma sak med js/morkt-lage.js, som står i sin helhet på modulbibliotekets sida. Den har en sak meny.js inte har: try och catch runt localStorage. Varför? Svaret står i kommentaren.
12. Ta det längre
För C och A i Projekt 5 räcker det inte att modulen fungerar. Här är tre spår.
Anpassa på riktigt – ändra beteendet, inte bara texten
Ta en modul och ändra något under ÄNDRA HÄR-zonen, medvetet och dokumenterat. Exempel som är lagom stora:
- Karusellen: låt piltangenterna Home och End hoppa till första och sista bilden.
- Filtret: låt knappen som redan är vald stänga av filtret igen när man klickar på den.
- Mörkt läge: lägg till ett tredje läge, "följ systemet", så att besökaren kan ta tillbaka sitt val.
Skriv i README.md vad du ändrade och varför. Det är den motiveringen C-nivån frågar efter.
Skriv modulen själv – A-spåret
Varje modul på modulbibliotekets sida har ett avsnitt Skriv den själv: en kravlista i tre till fem punkter, utan kod. Välj en modul, läs kraven, och skriv den från grunden utan att titta på originalet. Jämför sedan.
Det är inte samma sak som att kopiera och byta namn, och det är det A-spåret mäter: att du kan gå från krav till kod.
Gör modulen tillgänglig i det du redan byggt
Ta en modul du byggt in och gå igenom den med område 4:s verktyg: tabba genom den, kontrollera att fokus syns och följer läsordningen, kör WAVE. Hittar du något – rätta det och skriv ner vad det var. En modul som bryter tangentbordsnavigationen är en modul som gjort sajten sämre.
13. Felsökning
16 rader
| Symptom | Trolig orsak | Åtgärd |
|---|---|---|
| Ingenting händer, inget fel i konsolen | Filen hämtades aldrig | Fliken Network, leta efter din .js-fil. Står det 404 är sökvägen fel |
404 på .js-filen | Fel sökväg eller fel filnamn | Ligger filen i js/? Stämmer stora och små bokstäver? GitHub Pages skiljer på dem, din dator kanske inte |
Cannot read properties of null | Elementet hittades inte | Jämför klassnamnet i modulens ÄNDRA HÄR-zon med din HTML, tecken för tecken |
| Samma fel, men HTML:en ser rätt ut | Skriptet kördes för tidigt | Saknas defer i script-taggen? |
| Modulen fungerar på en sida men inte en annan | script-taggen saknas på den andra sidan | Varje sida behöver sin egen script-tagg |
| Modulen fungerar lokalt men inte på GitHub Pages | Stora och små bokstäver i filnamnet | Meny.js och meny.js är olika filer på servern |
| Knappen syns aldrig | Skriptet kom aldrig fram till raden som tar bort hidden | Titta i konsolen. Det finns ett fel ovanför |
| Knappen syns men gör inget | Lyssnaren sattes på fel element | Kontrollera att KNAPP pekar på knappen, inte på något runt omkring |
| Menyn går inte att stänga | Två script-taggar för samma fil | Sök i HTML:en. Modulen kördes två gånger och lyssnar två gånger |
| Filtret visar inga knappar | Inget element har data-grupp | Attributet ska sitta på det som ska filtreras, inte på filterraden |
| Karusellen visar alla bilder | Färre än två bilder, eller karusell-styr saknas | Modulen avslutar om något saknas. Jämför med demosidan |
| Formuläret skickas trots fel | novalidate sattes men lyssnaren kraschade | Läs konsolen. Ett fel i submit-funktionen stoppar preventDefault |
| Quizet säger "inte svarat" fast jag svarat | data-fraga och name hör inte ihop | Varje fieldset behöver data-fraga, och alla knappar i den samma name |
| Mörkt läge glöms bort | Privat fönster, eller NYCKEL ändrad | try/catch gör att det inte kraschar – men lagringen fungerar inte i alla lägen |
| Något ändras i konsolen men inte i filen | Konsolen ändrar bara den laddade sidan | Alla ändringar i konsolen försvinner vid omladdning. Skriv i filen |
Unexpected token | Tecken saknas | Titta på raden före den som anges. Oftast en } eller en ) |
14. Snabbreferens
| Vad | Så skriver du |
|---|---|
| Hitta ett element | document.querySelector(".klass") |
| Hitta alla | document.querySelectorAll("[data-grupp]") |
| Hitta på id | document.getElementById("innehall") |
| Leta uppåt efter närmaste | element.closest("button") |
| Byta text | element.textContent = "…" |
| Lägga till klass | element.classList.add("klar") |
| Ta bort klass | element.classList.remove("klar") |
| Växla klass | element.classList.toggle("klar") |
| Växla efter villkor | element.classList.toggle("klar", arRatt) |
| Sätta attribut | element.setAttribute("aria-expanded", "true") |
| Läsa attribut | element.getAttribute("aria-expanded") |
| Ta bort attribut | element.removeAttribute("aria-invalid") |
Läsa data--attribut | element.dataset.grupp |
| Göm / visa | element.hidden = true / false |
| Flytta fokus | element.focus() |
| Lyssna på händelse | element.addEventListener("click", function () { … }) |
| Stoppa standardbeteendet | handelse.preventDefault() |
| Vilken tangent | handelse.key === "Escape" |
| Varifrån händelsen kom | handelse.target |
| Gå igenom en lista | lista.forEach(function (del) { … }) |
| Gå igenom med index | lista.forEach(function (del, i) { … }) |
| Antal i en lista | lista.length |
| Villkor | if (villkor) { … } else { … } |
| Lika med | === |
| Inte | ! · Och: && · Eller: || |
| Skriva ut i konsolen | console.log("text", varde) |
| Koppla in filen | <script src="js/fil.js" defer></script> |
15. Ordlista
Ordträning
| Ord | Betyder |
|---|---|
| JavaScript | Programmeringsspråket som körs i webbläsaren och gör sidan interaktiv |
| modul | En färdig funktion i en egen fil, att koppla in och anpassa |
| DOM | Webbläsarens modell av sidan, som JavaScript läser och ändrar |
| selektor | Mönstret som pekar ut ett element: .klass, #id, [attribut] |
| element | En del av sidan: en knapp, ett stycke, en bild |
| variabel | Ett namn på ett värde |
const | Variabel vars namn aldrig pekar på något annat |
let | Variabel vars värde kommer att ändras |
| funktion | Några rader kod som fått ett namn och kan köras när man vill |
| anropa | Att köra en funktion, genom att skriva dess namn med parenteser |
| parameter | Ett värde en funktion tar emot |
| händelse | Något som sker: ett klick, en tangent, ett formulär som skickas |
| händelselyssnare | Kod som väntar på en händelse och svarar på den |
| händelsedelegering | Att lyssna på en förälder i stället för på varje barn |
| villkor | Kod som bara körs när något stämmer |
| loop | Kod som körs en gång per element i en lista |
| index | Ett elements plats i en lista. Börjar på 0 |
| objekt | Värden som hämtas med namn i stället för nummer |
null | Ingenting. Det querySelector ger när den inte hittar något |
true / false | Sant och falskt |
| kapsel | (function () { … })(); – gör allt inuti privat för filen |
"use strict" | Gör att stavfel blir fel i konsolen i stället för tysta buggar |
defer | Attribut på script som gör att koden körs när HTML:en är klar |
| konsolen | Webbläsarens meddelanderuta. F12 → Console |
console.log | Skriver ut ett värde i konsolen. Tas bort när du är klar |
localStorage | Litet lagringsutrymme i webbläsaren, kvar mellan besök |
| XSS | Säkerhetshålet som uppstår när text från utsidan tolkas som HTML |
| diskret funktionalitet | Att sidan fungerar utan JavaScript, och skripten förbättrar. Område 7 |