|
|
7 months ago | |
|---|---|---|
| .. | ||
| README.md | 7 months ago | |
| assignment.md | 7 months ago | |
README.md
Bygg en bankapp del 1: HTML-mallar och rutter i en webbapp
journey
title Din utvecklingsresa för bankappen
section SPA-grunder
Förstå enkelsidiga appar: 3: Student
Lär dig mallkoncept: 4: Student
Bemästra DOM-manipulation: 4: Student
section Rutteringssystem
Implementera klient-sidrouting: 4: Student
Hantera webbläsarhistorik: 5: Student
Skapa navigationssystem: 5: Student
section Professionella mönster
Bygg modulär arkitektur: 5: Student
Tillämpa bästa praxis: 5: Student
Skapa användarupplevelser: 5: Student
När Apollo 11:s styrdator navigerade till månen 1969, var den tvungen att växla mellan olika program utan att starta om hela systemet. Moderna webbapplikationer fungerar på liknande sätt – de ändrar vad du ser utan att ladda om allt från början. Detta skapar den smidiga, responsiva upplevelse som användare förväntar sig idag.
Till skillnad från traditionella webbplatser som laddar om hela sidor för varje interaktion, uppdaterar moderna webbappar endast de delar som behöver ändras. Detta tillvägagångssätt, ungefär som hur kontrollrummet byter mellan olika vyer samtidigt som kontakten bibehålls, skapar den flytande upplevelse vi vant oss vid.
Här är vad som gör skillnaden så dramatisk:
| Traditionella flersidiga appar | Moderna enkelsidiga appar |
|---|---|
| Navigering | Hela sidan laddas om för varje skärm |
| Prestanda | Långsammare på grund av fullständig HTML-nedladdning |
| Användarupplevelse | Ryckiga sidövergångar |
| Dataspridning | Svårt mellan sidor |
| Utveckling | Flera HTML-filer att underhålla |
Förstå utvecklingen:
- Traditionella appar kräver serverförfrågningar för varje navigeringshandling
- Moderna SPA:er laddar en gång och uppdaterar innehåll dynamiskt med JavaScript
- Användarnas förväntningar är idag för omedelbara, sömlösa interaktioner
- Prestandafördelar inkluderar reducerad bandbredd och snabbare svarstider
I den här lektionen bygger vi en bankapp med flera skärmar som flyter ihop sömlöst. Precis som forskare använder modulära instrument som kan konfigureras om för olika experiment, använder vi HTML-mallar som återanvändbara komponenter som visas vid behov.
Du kommer att arbeta med HTML-mallar (återanvändbara ritningar för olika skärmar), JavaScript-routing (systemet som växlar mellan skärmar) och webbläsarens history-API (som håller tillbaka-knappen fungerande som väntat). Dessa är samma grundläggande tekniker som används av ramverk som React, Vue och Angular.
I slutet kommer du att ha en fungerande bankapp som demonstrerar professionella principer för enkelsidiga applikationer.
mindmap
root((Single-Page Applikationer))
Architecture
Template System
Client-side Routing
State Management
Event Handling
Templates
Återanvändbara Komponenter
Dynamiskt Innehåll
DOM-Manipulation
Innehållsbyte
Routing
URL-Hantering
Historia API
Navigationslogik
Browser Integration
User Experience
Snabb Navigation
Mjuka Övergångar
Konsekvent Tillstånd
Moderna Interaktioner
Performance
Minskade Serverförfrågningar
Snabbare Sidövergångar
Effektiv Resursanvändning
Bättre Responsivitet
För-foreläsningsquiz
Vad du behöver
Vi kommer att behöva en lokal webbserver för att testa vår bankapp – oroa dig inte, det är lättare än det låter! Om du inte redan har en sådan installerad, installera bara Node.js och kör npx lite-server från din projektmapp. Det här praktiska kommandot startar en lokal server och öppnar automatiskt din app i webbläsaren.
Förberedelse
På din dator skapar du en mapp som heter bank med en fil som heter index.html inuti. Vi börjar med den här HTML boilerplate:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bank App</title>
</head>
<body>
<!-- This is where you'll work -->
</body>
</html>
Här är vad denna boilerplate ger:
- Fastställer HTML5-dokumentstruktur med korrekt DOCTYPE-deklaration
- Konfigurerar teckenkodning som UTF-8 för internationellt textstöd
- Aktiverar responsiv design med viewport-meta-taggen för mobilkompatibilitet
- Sätter en beskrivande titel som visas i webbläsarfliken
- Skapar en ren body-sektion där vi bygger vår applikation
📁 Förhandsvisning av projektstruktur
I slutet av denna lektion kommer ditt projekt att innehålla:
bank/ ├── index.html <!-- Main HTML with templates --> ├── app.js <!-- Routing and navigation logic --> └── style.css <!-- (Optional for future lessons) -->Filansvar:
- index.html: Innehåller alla mallar och tillhandahåller appens struktur
- app.js: Hanterar routing, navigering och mallhantering
- Mallar: Definierar UI för inloggning, dashboard och andra skärmar
HTML-mallar
Mallar löser en grundläggande utmaning inom webbutveckling. När Gutenberg uppfann boktryckarkonsten med rörliga typer på 1440-talet insåg han att istället för att snida ut hela sidor kunde han skapa återanvändbara bokstavsblock och arrangera dem vid behov. HTML-mallar fungerar på samma princip – istället för att skapa separata HTML-filer för varje skärm definierar man återanvändbara strukturer som kan visas vid behov.
flowchart TD
A["📋 Malldefinition"] --> B["💬 Gömda i DOM"]
B --> C["🔍 JavaScript Hittar Mall"]
C --> D["📋 Klona Mallinnehåll"]
D --> E["🔗 Fästa till Synlig DOM"]
E --> F["👁️ Användaren Ser Innehåll"]
G["Inloggningsmall"] --> A
H["Instrumentpanelsmall"] --> A
I["Framtida Mallar"] --> A
style A fill:#e3f2fd
style D fill:#e8f5e8
style F fill:#fff3e0
style B fill:#f3e5f5
Tänk på mallar som ritningar för olika delar av din app. Precis som en arkitekt skapar en ritning och använder den flera gånger istället för att rita identiska rum om och om igen, skapar vi mallar en gång och instansierar dem när det behövs. Webbläsaren håller dessa mallar dolda tills JavaScript aktiverar dem.
Om du vill skapa flera skärmar för en webbsida, skulle en lösning vara att skapa en HTML-fil för varje skärm du vill visa. Men denna lösning kommer med vissa nackdelar:
- Du måste ladda om hela HTML när du växlar skärm, vilket kan vara långsamt.
- Det är svårt att dela data mellan olika skärmar.
Ett annat tillvägagångssätt är att ha endast en HTML-fil och definiera flera HTML-mallar med hjälp av <template>-elementet. En mall är en återanvändbar HTML-block som inte visas av webbläsaren, och måste instansieras vid körning med JavaScript.
Låt oss bygga det
Vi ska skapa en bankapp med två huvudsakliga skärmar: en inloggningssida och en dashboard. Först lägger vi till ett platshållarelement i vår HTML-body – det är här alla våra olika skärmar kommer att visas:
<div id="app">Loading...</div>
Förstå denna platshållare:
- Skapar en container med ID "app" där alla skärmar kommer att visas
- Visar ett laddningsmeddelande tills JavaScript initierar första skärmen
- Tillhandahåller en enda monteringspunkt för vårt dynamiska innehåll
- Möjliggör enkel åtkomst från JavaScript med
document.getElementById()
💡 Proffstips: Eftersom innehållet i detta element kommer att ersättas kan vi lägga in ett laddningsmeddelande eller indikator som visas medan appen laddas.
Lägg sedan till nedan HTML-mallen för inloggningssidan. För tillfället lägger vi bara in en titel och en sektion innehållande en länk som vi ska använda för navigering.
<template id="login">
<h1>Bank App</h1>
<section>
<a href="/dashboard">Login</a>
</section>
</template>
Genomgång av denna inloggningsmall:
- Definierar en mall med unikt ID "login" för JavaScript-tillgång
- Innehåller en huvudrubrik som etablerar appens varumärke
- Har ett semantiskt
<section>-element för att gruppera relaterat innehåll - Tillhandahåller en navigeringslänk som leder användare till dashboarden
Sedan lägger vi till en annan HTML-mall för dashboard-sidan. Denna sida kommer att innehålla olika sektioner:
- En header med titel och en länk för utloggning
- Det nuvarande bankkontots saldo
- En lista över transaktioner, visade i en tabell
<template id="dashboard">
<header>
<h1>Bank App</h1>
<a href="/login">Logout</a>
</header>
<section>
Balance: 100$
</section>
<section>
<h2>Transactions</h2>
<table>
<thead>
<tr>
<th>Date</th>
<th>Object</th>
<th>Amount</th>
</tr>
</thead>
<tbody></tbody>
</table>
</section>
</template>
Låt oss förstå varje del av denna dashboard:
- Strukturerar sidan med ett semantiskt
<header>-element som innehåller navigation - Visar appens titel konsekvent över skärmar för varumärkesprofil
- Tillhandahåller en utloggningslänk som leder tillbaka till inloggningssidan
- Visar nuvarande kontosaldo i en dedikerad sektion
- Organiserar transaktionsdata med en korrekt strukturerad HTML-tabell
- Definierar tabellhuvuden för Datum, Objekt och Belopp
- Lämnar tabellkroppen tom för dynamisk innehållsinjektion senare
💡 Proffstips: När du skapar HTML-mallar, om du vill se hur det kommer att se ut, kan du kommentera ut
<template>och</template>-raderna genom att omsluta dem med<!-- -->.
🔄 Pedagogisk avstämning
Förståelse för mallsystemet: Innan du implementerar JavaScript, säkerställ att du förstår:
- ✅ Hur mallar skiljer sig från vanliga HTML-element
- ✅ Varför mallar förblir dolda tills de aktiveras av JavaScript
- ✅ Vikten av semantisk HTML-struktur i mallar
- ✅ Hur mallar möjliggör återanvändbara UI-komponenter
Snabb självtest: Vad händer om du tar bort <template>-taggarna runt din HTML?
Svar: Innehållet blir direkt synligt och förlorar sin mallfunktionalitet
Arkitekturfördelar: Mallar ger:
- Återanvändbarhet: En definition, flera instanser
- Prestanda: Ingen överflödig HTML-parsing
- Underhållbarhet: Centraliserad UI-struktur
- Flexibilitet: Dynamiskt innehållsbyte
✅ Varför tror du att vi använder id-attribut på mallarna? Skulle vi kunna använda något annat som klasser?
Göra mallarna levande med JavaScript
Nu behöver vi göra våra mallar funktionella. Precis som en 3D-skrivare tar en digital ritning och skapar ett fysiskt objekt, tar JavaScript våra dolda mallar och skapar synliga, interaktiva element som användare kan se och använda.
Processen följer tre genomgående steg som utgör grunden för modern webbutveckling. När du förstår detta mönster känner du igen det i många ramverk och bibliotek.
Om du provar din nuvarande HTML-fil i en webbläsare, ser du att den fastnar på att visa Loading.... Det beror på att vi behöver lägga till viss JavaScript-kod för att instansiera och visa HTML-mallarna.
Att instansiera en mall görs vanligtvis i 3 steg:
- Hämta mall-elementet i DOM, till exempel med
document.getElementById. - Klona mall-elementet, med
cloneNode. - Fäst det i DOM under ett synligt element, till exempel med
appendChild.
flowchart TD
A[🔍 Steg 1: Hitta mall] --> B[📋 Steg 2: Klona mall]
B --> C[🔗 Steg 3: Foga till DOM]
A1["document.getElementById('login')"] --> A
B1["template.content.cloneNode(true)"] --> B
C1["app.appendChild(view)"] --> C
C --> D[👁️ Mall synlig för användare]
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
Visuell genomgång av processen:
- Steg 1 hittar den dolda mallen i DOM-strukturen
- Steg 2 skapar en arbetskopia som säkert kan ändras
- Steg 3 infogar kopian i den synliga sidans område
- Resultat är en funktionell skärm som användare kan interagera med
✅ Varför behöver vi klona mallen innan vi fäster den i DOM? Vad tror du skulle hända om vi hoppade över detta steg?
Uppgift
Skapa en ny fil som heter app.js i din projektmapp och importera den filen i <head>-sektionen av din HTML:
<script src="app.js" defer></script>
Förstå denna script-import:
- Länkar JavaScript-filen till vårt HTML-dokument
- Använder
deferattributet för att säkerställa att skriptet körs efter att HTML-parsning är klar - Möjliggör åtkomst till alla DOM-element eftersom de laddats färdigt före skriptets körning
- Följer moderna bästa praxis för skriptladdning och prestanda
Nu i app.js skapar vi en ny funktion updateRoute:
function updateRoute(templateId) {
const template = document.getElementById(templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
Steg för steg, detta händer:
- Hittar mall-elementet med dess unika ID
- Skapar en djup kopia av mallens innehåll med
cloneNode(true) - Hittar app-containern där innehållet ska visas
- Rensar bort eventuellt befintligt innehåll från app-containern
- Infogar den klonade mallens innehåll i den synliga DOM
Anropa nu denna funktion med en av mallarna och titta på resultatet.
updateRoute('login');
Vad detta funktionsanrop åstadkommer:
- Aktiverar login-mallen genom att skicka dess ID som parameter
- Visar hur man programmerbart växlar mellan olika app-skärmar
- Visar inloggningsskärmen istället för meddelandet "Loading..."
✅ Vad är syftet med koden app.innerHTML = '';? Vad händer utan den?
Skapa rutter
Routing handlar egentligen om att koppla URL:er till rätt innehåll. Tänk dig hur tidiga telefonister använde kopplingsbord för att koppla samtal – de tog emot en förfrågan och kopplade den till rätt destination. Webbrouting fungerar på liknande sätt, den tar en URL-förfrågan och avgör vilket innehåll som ska visas.
flowchart LR
A["🌐 URL-sökväg<br/>/dashboard"] --> B["🗺️ Rutter Objekt<br/>Uppslag"]
B --> C["🎯 Mall-ID<br/>'dashboard'"]
C --> D["📌 Hitta Mall<br/>getElementById"]
D --> E["👁️ Visa Skärm<br/>Kopiera & Lägg till"]
F["📍 /login"] --> G["🎯 'login'"]
H["📍 /unknown"] --> I["❌ Hittades inte"]
I --> J["🔄 Omdirigera till /login"]
style B fill:#e3f2fd
style E fill:#e8f5e8
style I fill:#ffebee
style J fill:#fff3e0
Traditionellt hanterade webbservrar detta genom att servera olika HTML-filer för olika URL:er. Eftersom vi bygger en enkelsidig app behöver vi hantera denna routing själva med JavaScript. Detta ger oss mer kontroll över användarupplevelsen och prestandan.
flowchart LR
A["🌐 URL-väg<br/>/dashboard"] --> B["🗺️ Rutter Objekt<br/>Uppslagning"]
B --> C["🎯 Mall-ID<br/>'dashboard'"]
C --> D["📄 Hitta Mall<br/>getElementById"]
D --> E["👁️ Visa Skärm<br/>Klon & Bifoga"]
F["📍 /login"] --> G["🎯 'login'"]
H["📍 /unknown"] --> I["❌ Hittades inte"]
I --> J["🔄 Omdirigera till /login"]
style B fill:#e3f2fd
style E fill:#e8f5e8
style I fill:#ffebee
style J fill:#fff3e0
Förstå routningsflödet:
- URL-förändringar triggar en uppslagning i vår routes-konfiguration
- Giltiga rutter mappas till specifika mall-ID:n för renderering
- Ogiltiga rutter triggar fallback-beteende för att undvika trasiga tillstånd
- Mall-rendering följer den trestegsprocess vi lärde oss tidigare
När vi pratar om en webbapp kallar vi Routing viljan att koppla URL:er till specifika skärmar som ska visas. På en webbplats med flera HTML-filer görs detta automatiskt eftersom filvägar återspeglas i URL:en. Till exempel, med dessa filer i din projektmapp:
mywebsite/index.html
mywebsite/login.html
mywebsite/admin/index.html
Om du skapar en webbserver med mywebsite som rot, blir URL-mappningen:
https://site.com --> mywebsite/index.html
https://site.com/login.html --> mywebsite/login.html
https://site.com/admin/ --> mywebsite/admin/index.html
Men för vår webbapp använder vi en enda HTML-fil som innehåller alla skärmar, så detta standardbeteende hjälper oss inte. Vi måste skapa denna karta manuellt och uppdatera den visade mallen med JavaScript.
Uppgift
Vi använder ett enkelt objekt för att implementera en karta mellan URL-vägar och våra mallar. Lägg till detta objekt högst upp i din app.js-fil.
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard' },
};
Förstå denna routes-konfiguration:
- Definierar en mappning mellan URL-vägar och mallidentifikatorer
- Använder objektsyntax där nycklar är URL-vägar och värden innehåller mallinformation
- Möjliggör enkel uppslagning av vilken mall som ska visas för en given URL
- Tillhandahåller en skalbar struktur för att lägga till nya rutter framöver
Nu ska vi ändra lite på funktionen
updateRoute. Istället för att direkt skickatemplateIdsom argument vill vi hämta det genom att först titta på den aktuella URL:en, och sedan använda vår karta för att få motsvarande template ID-värde. Vi kan användawindow.location.pathnameför att enbart ta vägdelen från URL:en.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
const template = document.getElementById(route.templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
Nedbrytning av vad som sker här:
- Extraherar den aktuella vägen från webbläsarens URL med hjälp av
window.location.pathname - Slår upp motsvarande ruttkonfiguration i vårt routes-objekt
- Hämtar template ID från ruttkonfigurationen
- Följer samma template-renderingsprocess som tidigare
- Skapar ett dynamiskt system som svarar på URL-förändringar
Här har vi kartlagt de rutter vi deklarerat till motsvarande template. Du kan testa att det fungerar korrekt genom att manuellt ändra URL:en i din webbläsare.
✅ Vad händer om du skriver in en okänd väg i URL:en? Hur skulle vi kunna lösa det?
Lägga till navigering
Med routing på plats behöver användare ett sätt att navigera i appen. Traditionella webbplatser laddar om hela sidor när man klickar på länkar, men vi vill uppdatera både URL och innehåll utan siduppdatering. Det skapar en smidigare upplevelse, liknande hur skrivbordsapplikationer byter mellan olika vyer.
Vi behöver samordna två saker: att uppdatera webbläsarens URL så att användare kan bokmärka sidor och dela länkar, och att visa rätt innehåll. När det implementeras rätt blir navigeringen sömlös, som användare förväntar sig i moderna appar.
sequenceDiagram
participant User
participant Browser
participant App
participant Template
User->>Browser: Klickar på "Logga in"-länk
Browser->>App: onclick-händelse utlöst
App->>App: preventDefault() & navigera('/dashboard')
App->>Browser: history.pushState('/dashboard')
Browser->>Browser: URL uppdateras till /dashboard
App->>App: updateRoute() anropad
App->>Template: Hitta och klona dashboard-mall
Template->>App: Returnera klonat innehåll
App->>Browser: Ersätt appinnehåll med mall
Browser->>User: Visa dashboard-skärm
Note over User,Template: Användaren klickar på webbläsarens bakåtknapp
User->>Browser: Klickar på bakåtknappen
Browser->>Browser: Historiken går tillbaka till /login
Browser->>App: popstate-händelse utlöses
App->>App: updateRoute() anropas automatiskt
App->>Template: Hitta och klona login-mall
Template->>App: Returnera klonat innehåll
App->>Browser: Ersätt appinnehåll med mall
Browser->>User: Visa inloggningsskärm
🔄 Pedagogisk kontrollpunkt
Single-Page Application-arkitektur: Kontrollera att du förstår hela systemet:
- ✅ Hur skiljer sig klientbaserad routing från traditionell serverbaserad routing?
- ✅ Varför är History API viktigt för korrekt SPA-navigering?
- ✅ Hur möjliggör mallar dynamiskt innehåll utan siduppdateringar?
- ✅ Vilken roll spelar händelsehantering för att avlyssna navigation?
Systemintegration: Din SPA visar:
- Templatehantering: Återanvändbara UI-komponenter med dynamiskt innehåll
- Klientbaserad routing: URL-hantering utan serveranrop
- Händelsedriven arkitektur: Responsiv navigering och användarinteraktioner
- Webbläsarintegration: Bra stöd för historik- och framåt-/bakåtknappar
- Prestandaoptimering: Snabba övergångar och minskad serverbelastning
Professionella mönster: Du har implementerat:
- Modell-Vy-separation: Mallar separerade från applikationslogik
- Tillståndshantering: Synkronisering av URL-tillstånd med visat innehåll
- Progressiv förbättring: JavaScript förbättrar grundläggande HTML-funktionalitet
- Användarupplevelse: Smidig, app-liknande navigering utan siduppdateringar
<EFBFBD> Arkitekturinformation: Navigationssystemkomponenter
Vad du bygger:
- 🔄 URL-hantering: Uppdaterar adressfältet utan sidladdning
- 📋 Templatesystem: Växlar dynamiskt innehåll baserat på aktuell rutt
- 📚 Historikintegration: Behåller back-/forward-knappfunktionalitet
- 🛡️ Felhantering: Smidiga återfallslösningar för ogiltiga eller saknade rutter
Hur komponenter samverkar:
- Lyssnar på navigationshändelser (klick, historikändringar)
- Uppdaterar URL med hjälp av History API
- Renderar korrekt template för nya rutten
- Bibehåller en sömlös användarupplevelse hela tiden
Nästa steg för vår app är att lägga till möjlighet att navigera mellan sidor utan att behöva ändra URL manuellt. Det innebär två saker:
- Uppdatera den aktuella URL:en
- Uppdatera den visade templaten baserat på den nya URL:en
Vi har redan tagit hand om andra delen med funktionen updateRoute, så vi måste lista ut hur vi uppdaterar den aktuella URL:en.
Vi kommer att använda JavaScript och mer specifikt history.pushState som tillåter att uppdatera URL och skapa en ny post i webbläsarens historik utan att ladda om HTML:en.
⚠️ Viktigt: Medan HTML-ankarelementet
<a href>kan användas solo för att skapa länkar till olika URL:er, kommer det som standard att ladda om HTML när man klickar. Det är nödvändigt att hindra detta beteende vid routing med egen JavaScript, med funktionen preventDefault() i klickhändelsen.
Uppgift
Låt oss skapa en ny funktion som vi kan använda för att navigera i vår app:
function navigate(path) {
window.history.pushState({}, path, path);
updateRoute();
}
Förstå denna navigeringsfunktion:
- Uppdaterar webbläsarens URL till ny väg med
history.pushState - Lägger till en ny post i historikstacken för back-/forwardknappar
- Trigger funktionen
updateRoute()för att visa motsvarande template - Bibehåller single-page app-upplevelsen utan siduppdateringar
Denna metod uppdaterar först den aktuella URL:en utifrån den angivna vägen, sedan uppdateras templaten. Egenskapen window.location.origin returnerar URL-rot, vilket låter oss bygga upp en fullständig URL från en viss väg.
Nu när vi har denna funktion kan vi ta itu med problemet när en väg inte matchar någon definierad rutt. Vi modifierar updateRoute genom att lägga till ett fallback till en av befintliga rutter om vi inte hittar någon match.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
if (!route) {
return navigate('/login');
}
const template = document.getElementById(route.templateId);
const view = template.content.cloneNode(true);
const app = document.getElementById('app');
app.innerHTML = '';
app.appendChild(view);
}
Viktiga punkter att minnas:
- Kontrollerar om en rutt finns för den aktuella vägen
- Omdirigerar till inloggningssidan när en ogiltig rutt nås
- Ger en fallback-mekanism som förhindrar brutna navigeringar
- Säkerställer att användare alltid ser en giltig sida, även med felaktiga URL:er
Om ingen rutt hittas omdirigerar vi nu till sidan login.
Låt oss nu skapa en funktion som hämtar URL när en länk klickas och som stoppar webbläsarens standardlänkbeteende:
function onLinkClick(event) {
event.preventDefault();
navigate(event.target.href);
}
Nedbrytning av denna klickhanterare:
- Förhindrar webbläsarens standardlänkbeteende med
preventDefault() - Hämtar destinations-URL från den klickade länkens element
- Anropar vår egna navigate-funktion istället för att ladda om sidan
- Bibehåller en smidig single-page application-upplevelse
<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
...
<a href="/login" onclick="onLinkClick(event)">Logout</a>
Vad denna onclick-bindning åstadkommer:
- Kopplar varje länk till vårt egna navigationssystem
- Sänder klickhändelsen till vår funktion
onLinkClickför bearbetning - Möjliggör smidig navigering utan siduppdateringar
- Bibehåller korrekt URL-struktur som användare kan bokmärka och dela
Attributet onclick binder click-händelsen till JavaScript-kod, här anropet till funktionen navigate().
Testa att klicka på dessa länkar, du bör nu kunna navigera mellan olika vyer i din app.
✅ Metoden history.pushState är en del av HTML5-standarden och implementerad i alla moderna webbläsare. Om du skapar en webbapp för äldre webbläsare finns ett knep som kan användas istället: med en hash (#) före vägen kan du implementera routing som fungerar med vanlig ankarnavigation och inte laddar om sidan, eftersom dess syfte var att skapa interna länkar inom en sida.
Göra tillbaka- och framåtknapparna funktionella
Tillbaka- och framåtknappar är grundläggande för webbsurfning, precis som NASA:s kontrollrum kan granska tidigare systemtillstånd under rymduppdrag. Användare förväntar sig att dessa knappar fungerar; om de inte gör det bryts förväntad surfupplevelse.
Vår single-page app behöver extra konfiguration för att stödja detta. Webbläsaren håller en historikstack (som vi lagt till med history.pushState), men när användare navigerar historiken måste appen svara med att uppdatera visat innehåll enligt detta.
sequenceDiagram
participant User
participant Browser
participant App
participant Template
User->>Browser: Klickar på "Logga in"-länk
Browser->>App: onclick-händelse utlöses
App->>App: preventDefault() & navigera('/dashboard')
App->>Browser: history.pushState('/dashboard')
Browser->>Browser: URL uppdateras till /dashboard
App->>App: updateRoute() anropas
App->>Template: Hitta & klona dashboard-mall
Template->>App: Returnerar klonat innehåll
App->>Browser: Ersätt appinnehåll med mall
Browser->>User: Visa dashboard-skärm
Note over User,Template: Användaren klickar på webbläsarens bakåtknapp
User->>Browser: Klickar på bakåtknapp
Browser->>Browser: Historiken går tillbaka till /login
Browser->>App: popstate-händelse utlöses
App->>App: updateRoute() anropas automatiskt
App->>Template: Hitta & klona login-mall
Template->>App: Returnerar klonat innehåll
App->>Browser: Ersätt appinnehåll med mall
Browser->>User: Visa inloggningsskärm
Viktiga interaktionspunkter:
- Användaråtgärder initierar navigation via klick eller webbläsarknappar
- Appen avlyssnar klick på länkar för att förhindra sidladdningar
- History API hanterar URL-förändringar och historikstack
- Templates tillhandahåller innehåll för varje sida
- Eventlyssnare ser till att appen svarar på alla navigeringssätt
Användningen av history.pushState skapar nya poster i webbläsarens navigationshistorik. Du kan kontrollera detta genom att hålla inne tillbaka-knappen i din webbläsare, den bör visa något liknande:
Om du klickar på tillbaka-knappen några gånger kommer du se att den aktuella URL:en ändras och historiken uppdateras, men samma template fortsätter att visas.
Detta beror på att applikationen inte vet att vi måste anropa updateRoute() varje gång historiken ändras. Om du tittar i dokumentationen för history.pushState ser du att om tillståndet ändras – alltså om vi gått till en annan URL – triggas ett popstate-event. Vi ska använda det för att fixa detta problem.
Uppgift
För att se till att rätt template visas när webbläsarhistoriken ändras ska vi koppla en funktion som anropar updateRoute(). Det gör vi längst ned i vår app.js-fil:
window.onpopstate = () => updateRoute();
updateRoute();
Förstå denna historikintegration:
- Lyssnar på
popstate-händelser som uppstår när användare navigerar med webbläsarknappar - Använder en arrowfunktion för kortfattad syntax i eventhanteraren
- Anropar automatiskt
updateRoute()när historikens tillstånd ändras - Initierar appen genom att anropa
updateRoute()när sidan laddas - Säkerställer att rätt template visas oavsett hur användaren navigerar
💡 Proffstips: Vi använde en arrowfunktion här för att deklarera vår
popstate-eventhanterare för korthet, men en vanlig funktion skulle fungera lika bra.
Här är en repetitionsvideo om arrowfunktioner:
🎥 Klicka på bilden ovan för en video om arrowfunktioner.
Testa nu att använda tillbaka- och framåtknapparna i din webbläsare, och se till att visad rutt uppdateras korrekt den här gången.
⚡ Vad du kan göra de närmaste 5 minuterna
- Testa navigeringen i din bankapp med webbläsarens bakåt-/framåtknappar
- Prova att skriva olika URL:er manuellt i adressfältet för att testa routing
- Öppna webbläsarens DevTools och inspektera hur mallar klonas in i DOM
- Experimentera med att lägga till console.log-utskrifter för att följa routingflödet
🎯 Vad du kan åstadkomma under denna timme
- Klara efter-lektionsquizzen och förstå SPA-arkitekturkoncept
- Lägg till CSS-styling för att göra dina bankapp-mallar professionella
- Implementera en 404-felsida med korrekt felhantering
- Skapa en credits-sida med extra routingfunktionalitet
- Lägg till laddningstillstånd och övergångar mellan mallbyten
📅 Din veckolånga SPA-utvecklingsresa
- Bygg en komplett bankapp med formulär, databehandling och persistens
- Lägg till avancerade routingfunktioner som ruttparametrar och nästlade rutter
- Implementera navigation guards och autentiseringsbaserad routing
- Skapa återanvändbara templatekomponenter och ett komponentbibliotek
- Lägg till animationer och övergångar för mjukare användarupplevelse
- Distribuera din SPA till en hostingtjänst och konfigurera routing korrekt
🌟 Din månads långa frontendarkitektur-mästarklass
- Bygg komplexa SPA:er med moderna ramverk som React, Vue eller Angular
- Lär dig avancerade mönster och bibliotek för tillståndshantering
- Bemästra byggverktyg och utvecklingsflöden för SPA-utveckling
- Implementera Progressive Web App-funktioner och offline-stöd
- Studera prestandaoptimeringstekniker för stora SPA:er
- Bidra till öppna källkodsprojekt för SPA:er och dela din kunskap
🎯 Din tidslinje för att behärska Single-Page Applications
timeline
title SPA-utveckling & Modern Webbarkitektur Lärande Progression
section Grundläggande (20 minuter)
Mallsystem: HTML-mallelement
: DOM-manipulering
: Innehållskloning
: Dynamisk rendering
section Routing Grunder (30 minuter)
Klientsidesnavigering: URL-hantering
: History API
: Ruttmappning
: Händelsehantering
section Användarupplevelse (40 minuter)
Navigationsfinslipning: Webbläsarintegration
: Tillbaka-knapp stöd
: Felhantering
: Smidiga övergångar
section Arkitekturmönster (50 minuter)
Professionella SPA: Komponentsystem
: Tillståndshantering
: Prestandaoptimering
: Felgränser
section Avancerade Tekniker (1 vecka)
Ramverksintegration: React Router
: Vue Router
: Angular Router
: Tillståndsbibliotek
section Produktionsfärdigheter (1 månad)
Företagsutveckling: Byggsystem
: Teststrategier
: Implementeringspipelines
: Prestandaövervakning
🛠️ Din kompilering av verktyg för SPA-utveckling
Efter denna lektion har du nu bemästrat:
- Templatearkitektur: Återanvändbara HTML-komponenter med dynamisk innehållsrendering
- Klientbaserad routing: URL-hantering och navigation utan siduppdateringar
- Webbläsarintegration: Användning av History API och back-/forward-knappstöd
- Händelsedrivna system: Navigationshantering och användarinteraktionsstyrning
- DOM-manipulation: Mallkloning, bytesinnehåll och elementhantering
- Felhantering: Smidiga återfallslösningar för ogiltiga rutter och saknat innehåll
- Prestandamönster: Effektiv innehållsladdning och renderingsstrategier
Tillämpningar i verkliga livet: Dina SPA-utvecklingsfärdigheter är direkt användbara för:
- Moderna webbapplikationer: React, Vue, Angular och andra ramverksutvecklingar
- Progressiva webbappar: Offline-kapabla appar med appliknande upplevelser
- Företagsdashboards: Komplexa affärsappar med flera vyer
- E-handelsplattformar: Produktkataloger, kundvagnar och kassaflöden
- Innehållshantering: Dynamisk innehållsskapande och redigeringsgränssnitt
- Mobilutveckling: Hybridappar som använder webteknologier
Professionella färdigheter du fått: Du kan nu:
- Arkitektera enskilda-sidapplikationer med korrekt separering av ansvarsområden
- Implementera klientsidesroutningssystem som skalas med applikationens komplexitet
- Felsöka komplexa navigationsflöden med webbläsarens utvecklarverktyg
- Optimera applikationsprestanda genom effektiv mallhantering
- Designa användarupplevelser som känns inhemska och responsiva
Behärskade frontendutvecklingskoncept:
- Komponentarkitektur: Återanvändbara UI-mönster och mallsystem
- Status-synkronisering: URL-statushantering och webbläsarens historik
- Händelsestyrd programmering: Hantering av användarinteraktioner och navigering
- Prestandaoptimering: Effektiv DOM-manipulation och innehållsladdning
- Användarupplevelsedesign: Smidiga övergångar och intuitiv navigering
Nästa steg: Du är redo att utforska moderna frontendramverk, avancerad status-hantering eller bygga komplexa företagsapplikationer!
🌟 Prestationsupplåst: Du har byggt en professionell grund för en enskild-sidapplikation med moderna webbarkitektur-mönster!
GitHub Copilot Agent-utmaning 🚀
Använd Agent-läget för att slutföra följande utmaning:
Beskrivning: Förbättra bankappen genom att implementera felhantering och en 404-sidmall för ogiltiga rutter, vilket förbättrar användarupplevelsen vid navigering till icke-existerande sidor.
Uppmaning: Skapa en ny HTML-mall med id "not-found" som visar en användarvänlig 404-felsida med styling. Modifiera sedan JavaScript-routningslogiken för att visa denna mall när användarna navigerar till ogiltiga URL:er, och lägg till en "Gå hem"-knapp som navigerar tillbaka till inloggningssidan.
Läs mer om agent mode här.
🚀 Utmaning
Lägg till en ny mall och rutt för en tredje sida som visar krediter för denna app.
Utmaningsmål:
- Skapa en ny HTML-mall med lämplig innehållsstruktur
- Lägg till den nya rutten i din ruttkonfigurationsobjekt
- Inkludera navigationslänkar till och från krediter-sidan
- Testa att all navigering fungerar korrekt med webbläsarens historik
Quiz efter föreläsning
Granskning & Självstudier
Routing är en av de överraskande knepiga delarna av webbutveckling, särskilt när webben går från siduppdateringar till Single Page Application-siduppdateringar. Läs lite om hur Azure Static Web App-tjänsten hanterar routing. Kan du förklara varför några av de beslut som beskrivs i detta dokument är nödvändiga?
Ytterligare lärresurser:
- Utforska hur populära ramverk som React Router och Vue Router implementerar klientsidesrouting
- Forska i skillnaderna mellan hashbaserad routing och history API-routing
- Lär dig om serversidesrendering (SSR) och hur det påverkar routingstrategier
- Undersök hur progressiva webbappar (PWA) hanterar routing och navigering
Uppgift
Friskrivning: Detta dokument har översatts med hjälp av AI-översättningstjänsten Co-op Translator. Vi strävar efter noggrannhet, men var medveten om att automatiska översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess modersmål bör anses vara den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för några missförstånd eller feltolkningar som uppstår från användningen av denna översättning.

