15 KiB
MVC Nettbutikk Applikasjon
En ren JavaScript-implementering av en nettbutikk som bruker Model-View-Controller (MVC) arkitekturmønsteret. Dette utdanningsprosjektet demonstrerer kjerne webutviklingskonsepter uten eksterne rammeverk.
🏗️ Arkitekturoversikt
Denne applikasjonen følger MVC-mønsteret med et sentralisert view-renderingssystem:
- Model: Håndterer databehandling og forretningslogikk
- View: Administrerer HTML-generering og DOM-manipulering
- Controller: Koordinerer brukerinteraksjoner og dataflyt
📊 UML Diagrammer
Klassediagram
classDiagram
class Model {
-products: Array~Product~
-cart: Array~CartItem~
+getAllProducts() Array~Product~
+getProductById(id) Product
+addToCart(productId, quantity) boolean
+removeFromCart(productId) void
+updateCartQuantity(productId, quantity) void
+getCart() Array~CartItem~
+getCartTotal() number
+getCartItemCount() number
+clearCart() void
+saveCartToStorage() void
+loadCartFromStorage() Array~CartItem~
+initializeCart() void
}
class View {
-currentPage: string
-cartCount: number
+updateView(viewType, data) void
+generateNavbar() string
+generateProductsPage(products) string
+generateProductDetailPage(product) string
+generateCartPage(cartItems, total, itemCount) string
+createProductCard(product) string
+createCartItem(item) string
+attachEventListeners() void
+updateCartCountInNav() void
+showNotification(message) void
}
class Controller {
+loadProducts() void
+showProductDetail(productId) void
+handleAddToCart(productId) void
+handleRemoveFromCart(productId) void
+changeQuantity(productId, change) void
+handleClearCart() void
+navigateToProducts() void
+navigateToCart() void
+updateCartDisplay() void
}
class Product {
+id: number
+name: string
+price: number
+description: string
+image: string
+category: string
}
class CartItem {
+productId: number
+quantity: number
+product: Product
}
class App {
+initialize() void
}
Controller --> Model : bruker
Controller --> View : oppdaterer
View --> Controller : sender hendelser
Model --> Product : inneholder
Model --> CartItem : administrerer
CartItem --> Product : refererer til
App --> Controller : initialiserer
App --> Model : setter opp
App --> View : starter
Sekvensdiagram - Legg til i handlekurv
sequenceDiagram
participant U as Bruker
participant V as View
participant C as Controller
participant M as Model
U->>V: Klikker "Legg i handlekurv"
V->>C: handleAddToCart(productId)
C->>M: addToCart(productId)
M->>M: getProductById(productId)
M->>M: Finn eksisterende element eller lag nytt
M->>M: saveCartToStorage()
M-->>C: return true/false
alt Vellykket
C->>M: getProductById(productId)
M-->>C: return product
C->>V: updateView('notification', {message})
C->>C: updateCartDisplay()
C->>M: getCart()
M-->>C: return cart
C->>M: getCartTotal()
M-->>C: return total
C->>M: getCartItemCount()
M-->>C: return itemCount
C->>V: updateView('cart', {cartItems, total, itemCount})
C->>V: updateView('cart-count', {count})
V->>V: generateCartPage() eller updateCartCountInNav()
V-->>U: Oppdatert UI med notifikasjon
else Feilet
C->>V: updateView('notification', {message: 'Feil'})
V-->>U: Feilmelding
end
📁 Prosjektstruktur
mvc-emne2/
├── index.html # Hoved HTML-fil med enkelt app-container
├── styles.css # Applikasjonsstyling
├── js/
│ ├── app.js # Applikasjonsinitialisering
│ ├── model.js # Datalag og forretningslogikk
│ ├── view.js # UI-rendering og HTML-generering
│ └── controller.js # Brukerinteraksjonshåndtering
├── flow-diagram.md # Applikasjonsflytvisualisering
├── README.md # Engelsk dokumentasjon
├── README-NO.md # Norsk dokumentasjon (denne filen)
└── ACCESSIBILITY.md # Tilgjengelighetsdokumentasjon
🔧 Nøkkelkomponenter
1. Model (model.js
)
Formål: Administrerer applikasjonsdata og persistering
Nøkkelfunksjoner:
getAllProducts()
- Returnerer produktkataloggetProductById(id)
- Henter spesifikt produktaddToCart(productId, quantity)
- Legger til varer i handlekurvremoveFromCart(productId)
- Fjerner varer fra handlekurvupdateCartQuantity(productId, quantity)
- Oppdaterer vareantallgetCart()
- Returnerer gjeldende handlekurvinnholdgetCartTotal()
- Beregner total handlekurvprisgetCartItemCount()
- Returnerer totalt antall varerclearCart()
- Tømmer handlekurvensaveCartToStorage()
/loadCartFromStorage()
- LocalStorage-persistering
Datastruktur:
// Produkt
{
id: number,
name: string,
price: number,
description: string,
image: string (emoji),
category: string
}
// Handlekurvvare
{
productId: number,
quantity: number,
product: Product
}
2. View (view.js
)
Formål: Håndterer all UI-rendering gjennom en sentralisert updateView
-funksjon
Kjernearkitektur:
function updateView(viewType, data = {}) {
switch (viewType) {
case 'products': // Rendrer produktliste
case 'product-detail': // Rendrer enkelt produkt
case 'cart': // Rendrer handlekurv
case 'cart-count': // Oppdater handlekurvmerke
case 'notification': // Vis brukermeldinger
}
}
Nøkkelfunksjoner:
- Enkelt inngangspunkt: All rendering går gjennom
updateView()
- Komplett sidegenerering: Genererer hele side-HTML inkludert navigasjon
- Event Listener-administrasjon: Fester automatisk event listeners etter hver rendering
- Mallfunksjoner: Modulære HTML-genereringsfunksjoner
HTML-genereringsfunksjoner:
generateNavbar()
- Lager navigasjonsheadergenerateProductsPage(products)
- ProduktlistesidegenerateProductDetailPage(product)
- ProduktdetaljsidegenerateCartPage(cartItems, total, itemCount)
- HandlekurvsidecreateProductCard(product)
- Individuelt produktkortcreateCartItem(item)
- Individuell handlekurvvare
3. Controller (controller.js
)
Formål: Håndterer brukerinteraksjoner og koordinerer mellom Model og View
Navigasjonsfunksjoner:
navigateToProducts()
- Viser produktlistenavigateToCart()
- Viser handlekurvshowProductDetail(productId)
- Viser produktdetaljer
Handlekurvadministrasjon:
handleAddToCart(productId)
- Legger til produkt i handlekurvhandleRemoveFromCart(productId)
- Fjerner produkt fra handlekurvchangeQuantity(productId, change)
- Oppdaterer produktantallhandleClearCart()
- Tømmer hele handlekurvenupdateCartDisplay()
- Oppdaterer handlekurvvisning og teller
Nøkkeldesignmønstre:
- Alle funksjoner kaller
updateView()
for UI-oppdateringer - Brukernotifikasjoner håndteres konsistent
- Handlekurvtilstand persisteres automatisk etter endringer
4. Applikasjonsinitialisering (app.js
)
Formål: Bootstrapper applikasjonen
Initialiseringsflyt:
- Vent på at DOM skal laste
- Initialiser handlekurv fra localStorage
- Last produkter fra model
- Renderer initial produktside
- Oppdater handlekurvteller
document.addEventListener('DOMContentLoaded', function() {
// Fjern lastingstilstand
const loadingElement = document.querySelector('.loading');
if (loadingElement) {
loadingElement.remove();
}
initializeCart();
const products = getAllProducts();
const itemCount = getCartItemCount();
updateView('products', { products });
updateView('cart-count', { count: itemCount });
console.log('Nettbutikk MVC Demo initialisert!');
});
🔄 Dataflyt
1. Applikasjonsoppstart
HTML-lasting → DOMContentLoaded → initializeCart() → loadCartFromStorage() →
getAllProducts() → updateView('products') → generateProductsPage() → attachEventListeners()
2. Brukerinteraksjoner
Brukerklikk → Controller-funksjon → Model-operasjon → updateView() →
HTML-generering → Event Listener-tilkobling → UI-oppdatering
3. Handlekurvoperasjoner
Legg til i handlekurv → addToCart() → saveCartToStorage() → updateCartDisplay() →
updateView('cart') + updateView('cart-count') → showNotification()
🎨 View-renderingssystem
Sentralisert rendering
Alle UI-oppdateringer flyter gjennom den enkelte updateView()
-funksjonen:
updateView('products', { products: [...] });
updateView('product-detail', { product: {...} });
updateView('cart', { cartItems: [...], total: 0, itemCount: 0 });
updateView('cart-count', { count: 0 });
updateView('notification', { message: 'Vellykket!' });
Komplett sidegenerering
I motsetning til tradisjonell DOM-manipulering genererer dette systemet komplett side-HTML:
function generateProductsPage(products) {
return `
${generateNavbar()}
<main>
<section class="page active">
<h2>Våre Produkter</h2>
<div class="products-grid">
${products.map(product => createProductCard(product)).join('')}
</div>
</section>
</main>
`;
}
Event Listener-administrasjon
Etter hver rendering festes event listeners på nytt:
function attachEventListeners() {
const productsLink = document.querySelector('[data-page="products"]');
const cartLink = document.querySelector('[data-page="cart"]');
if (productsLink) {
productsLink.addEventListener('click', function(e) {
e.preventDefault();
navigateToProducts();
});
}
// ... flere listeners
}
💾 Datapersistering
LocalStorage-integrasjon
Handlekurvdata persisteres automatisk:
function saveCartToStorage() {
try {
localStorage.setItem('webstore_cart', JSON.stringify(cart));
} catch (error) {
console.error('Feil ved lagring av handlekurv til localStorage:', error);
}
}
function loadCartFromStorage() {
try {
const savedCart = localStorage.getItem('webstore_cart');
if (savedCart) {
const parsedCart = JSON.parse(savedCart);
return parsedCart.map(item => ({
...item,
product: products.find(p => p.id === item.productId) ||
{ id: item.productId, name: 'Ukjent Produkt', price: 0 }
}));
}
} catch (error) {
console.error('Feil ved lasting av handlekurv fra localStorage:', error);
}
return [];
}
🚀 Bruk
Kjøring av applikasjonen
- Åpne
index.html
i en nettleser - Applikasjonen initialiseres automatisk
- Naviger mellom produkter, produktdetaljer og handlekurv
- Handlekurvtilstand persisteres på tvers av nettlesersesjoner
Nøkkelfunksjoner
- Produktbrowsing: Vis alle produkter i rutenettlayout
- Produktdetaljer: Klikk på hvilket som helst produkt for detaljert visning
- Handlekurv: Legg til, fjern og modifiser antall
- Persistent handlekurv: Handlekurvinnhold lagret i localStorage
- Responsiv design: Fungerer på desktop og mobil
- Brukernotifikasjoner: Tilbakemelding for alle brukerhandlinger
♿ Tilgjengelighet og semantisk HTML
Applikasjonen er bygget med tilgjengelighet i fokus:
Semantiske HTML-elementer
<main>
,<header>
,<footer>
,<nav>
,<section>
,<article>
- Riktig heading-hierarki (
<h1>
,<h2>
,<h3>
) - Beskrivende ARIA-attributter
ARIA-funksjoner
role
-attributter for klargjøring av elementfunksjoneraria-label
for beskrivende etiketteraria-live
for dynamiske innholdsoppdateringeraria-describedby
for tilleggsinformasjon
Tastaturnavigasjon
- Alle interaktive elementer er tilgjengelige via tastatur
- Fokusindikatorer for alle interaktive elementer
- Logisk tab-rekkefølge
🎯 Utdanningsmessige fordeler
MVC-mønsterdemonstrasjon
- Tydelig separasjon av ansvar
- Model håndterer data, View håndterer presentasjon, Controller håndterer logikk
- Demonstrerer hvordan komponenter samhandler i MVC-arkitektur
Moderne JavaScript-funksjoner
- ES6+-syntaks (arrow-funksjoner, template literals, destructuring)
- LocalStorage API-bruk
- Event handling-mønstre
- Funksjonelle programmeringskonsepter
Webutviklingsfundamentaler
- DOM-manipuleringsteknikker
- Event listener-administrasjon
- Klientsidehåndtering av tilstand
- HTML-generering og templating
- CSS-stylingintegrasjon
🔧 Tekniske beslutninger
Hvorfor sentralisert rendering?
- Konsistens: Alle UI-oppdateringer følger samme mønster
- Vedlikeholdbarhet: Lett å spore og debugge UI-endringer
- Skalerbarhet: Enkelt å legge til nye visningstyper
- Tilstandshåndtering: Klar dataflyt fra model til view
Hvorfor komplett sidegenerering?
- Enkelhet: Ingen kompleks DOM-diffing eller tilstandssporing
- Pålitelighet: Fresh render eliminerer foreldede tilstandsproblemer
- Ytelse: Moderne nettlesere håndterer innerHTML effektivt
- Debugging: Lett å se nøyaktig hvilken HTML som genereres
Hvorfor LocalStorage?
- Persistering: Handlekurv overlever nettleseroppstart
- Enkelhet: Ingen serversidekompleksitet
- Ytelse: Øyeblikkelige lastetider
- Utdanningsmessig: Demonstrerer klientsidelagringskonsepter
🎨 Stylingarkitektur
Applikasjonen bruker et rent, moderne CSS-design:
- Responsive rutenettlayouter
- Kortbasert produktvisning
- Konsistent knapp- og formstiling
- Mobilvennlig navigasjon
- Glatte overganger og hover-effekter
🔮 Fremtidige forbedringer
Denne MVC-implementeringen fungerer som et grunnlag for progressiv forbedring:
- Fase 2: Legg til TypeScript for typesikkerhet
- Fase 3: Implementer Vue.js for reaktiv UI
- Fase 4: Legg til brukerautentisering
- Fase 5: Integrer betalingsbehandling
- Fase 6: Legg til produktsøk og filtrering
- Fase 7: Implementer ekte backend-API
📚 Læringsutbytte
Ved å studere denne kodebasen vil du forstå:
- MVC-arkitekturmønsterimplementering
- Klientsidehåndtering av tilstand
- Moderne JavaScript-utviklingspraksis
- HTML-generering og templating-tilnærminger
- Hendelsesdrevne programmeringsmønstre
- LocalStorage API-bruk
- Responsive webdesignprinsipper
- Tilgjengelighetsstandarder og semantisk HTML
Dette prosjektet er en del av GET Frontend-utviklingslæreplanen og demonstrerer kjerne webutviklingskonsepter gjennom praktisk implementering.