16 KiB
Construirea unei aplicații bancare Partea 1: Șabloane HTML și rute într-o aplicație web
Chestionar înainte de lecție
Introducere
De la apariția JavaScript în browsere, site-urile web au devenit mai interactive și mai complexe ca niciodată. Tehnologiile web sunt acum utilizate frecvent pentru a crea aplicații complet funcționale care rulează direct în browser, pe care le numim aplicații web. Deoarece aplicațiile web sunt extrem de interactive, utilizatorii nu doresc să aștepte reîncărcarea completă a paginii de fiecare dată când se efectuează o acțiune. De aceea, JavaScript este utilizat pentru a actualiza HTML-ul direct folosind DOM, oferind o experiență mai fluidă utilizatorului.
În această lecție, vom pune bazele pentru a crea o aplicație bancară web, utilizând șabloane HTML pentru a crea mai multe ecrane care pot fi afișate și actualizate fără a fi nevoie să reîncărcăm întreaga pagină HTML.
Cerințe preliminare
Ai nevoie de un server web local pentru a testa aplicația web pe care o vom construi în această lecție. Dacă nu ai unul, poți instala Node.js și utiliza comanda npx lite-server
din folderul proiectului tău. Aceasta va crea un server web local și va deschide aplicația ta într-un browser.
Pregătire
Pe computerul tău, creează un folder numit bank
cu un fișier numit index.html
în interiorul său. Vom începe cu acest boilerplate HTML:
<!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>
Șabloane HTML
Dacă dorești să creezi mai multe ecrane pentru o pagină web, o soluție ar fi să creezi un fișier HTML pentru fiecare ecran pe care vrei să-l afișezi. Totuși, această soluție vine cu unele inconveniente:
- Trebuie să reîncarci întregul HTML atunci când schimbi ecranul, ceea ce poate fi lent.
- Este dificil să partajezi date între diferitele ecrane.
O altă abordare este să ai un singur fișier HTML și să definești mai multe șabloane HTML folosind elementul <template>
. Un șablon este un bloc HTML reutilizabil care nu este afișat de browser și trebuie instanțiat la runtime folosind JavaScript.
Sarcină
Vom crea o aplicație bancară cu două ecrane: pagina de autentificare și tabloul de bord. Mai întâi, să adăugăm în corpul HTML un element de tip placeholder pe care îl vom folosi pentru a instanția diferitele ecrane ale aplicației noastre:
<div id="app">Loading...</div>
I-am atribuit un id
pentru a fi mai ușor de localizat cu JavaScript mai târziu.
Sfat: deoarece conținutul acestui element va fi înlocuit, putem pune un mesaj de încărcare sau un indicator care va fi afișat în timp ce aplicația se încarcă.
Apoi, să adăugăm mai jos șablonul HTML pentru pagina de autentificare. Deocamdată vom pune doar un titlu și o secțiune care conține un link pe care îl vom folosi pentru navigare.
<template id="login">
<h1>Bank App</h1>
<section>
<a href="/dashboard">Login</a>
</section>
</template>
După aceea, vom adăuga un alt șablon HTML pentru pagina tabloului de bord. Această pagină va conține diferite secțiuni:
- Un antet cu un titlu și un link de deconectare
- Soldul curent al contului bancar
- O listă de tranzacții, afișată într-un tabel
<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>
Sfat: când creezi șabloane HTML, dacă vrei să vezi cum arată, poți comenta liniile
<template>
și</template>
înconjurându-le cu<!-- -->
.
✅ De ce crezi că folosim atributele id
pe șabloane? Am putea folosi altceva, cum ar fi clasele?
Afișarea șabloanelor cu JavaScript
Dacă încerci fișierul HTML curent într-un browser, vei vedea că rămâne blocat afișând Loading...
. Asta pentru că trebuie să adăugăm cod JavaScript pentru a instanția și afișa șabloanele HTML.
Instanțierea unui șablon se face de obicei în 3 pași:
- Recuperarea elementului șablon din DOM, de exemplu folosind
document.getElementById
. - Clonarea elementului șablon, folosind
cloneNode
. - Atașarea acestuia la DOM sub un element vizibil, de exemplu folosind
appendChild
.
✅ De ce trebuie să clonăm șablonul înainte de a-l atașa la DOM? Ce crezi că s-ar întâmpla dacă am sări peste acest pas?
Sarcină
Creează un fișier nou numit app.js
în folderul proiectului tău și importă acel fișier în secțiunea <head>
a HTML-ului:
<script src="app.js" defer></script>
Acum, în app.js
, vom crea o funcție nouă 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);
}
Ceea ce facem aici sunt exact cei 3 pași descriși mai sus. Instanțiem șablonul cu id-ul templateId
și punem conținutul clonat în placeholder-ul aplicației noastre. Observă că trebuie să folosim cloneNode(true)
pentru a copia întreaga subarbore a șablonului.
Acum, apelează această funcție cu unul dintre șabloane și privește rezultatul.
updateRoute('login');
✅ Care este scopul acestui cod app.innerHTML = '';
? Ce se întâmplă fără el?
Crearea rutelor
Când vorbim despre o aplicație web, numim Routing intenția de a mapa URL-urile la ecranele specifice care ar trebui afișate. Pe un site web cu mai multe fișiere HTML, acest lucru se face automat, deoarece căile fișierelor sunt reflectate în URL. De exemplu, cu aceste fișiere în folderul proiectului tău:
mywebsite/index.html
mywebsite/login.html
mywebsite/admin/index.html
Dacă creezi un server web cu mywebsite
ca root, maparea URL-urilor va fi:
https://site.com --> mywebsite/index.html
https://site.com/login.html --> mywebsite/login.html
https://site.com/admin/ --> mywebsite/admin/index.html
Totuși, pentru aplicația noastră web folosim un singur fișier HTML care conține toate ecranele, așa că acest comportament implicit nu ne va ajuta. Trebuie să creăm această mapare manual și să actualizăm șablonul afișat folosind JavaScript.
Sarcină
Vom folosi un obiect simplu pentru a implementa o mapare între căile URL și șabloanele noastre. Adaugă acest obiect în partea de sus a fișierului app.js
.
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard' },
};
Acum să modificăm puțin funcția updateRoute
. În loc să trecem direct templateId
ca argument, vrem să-l recuperăm mai întâi uitându-ne la URL-ul curent și apoi să folosim maparea noastră pentru a obține valoarea corespunzătoare a id-ului șablonului. Putem folosi window.location.pathname
pentru a obține doar secțiunea de cale din URL.
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);
}
Aici am mapat rutele declarate la șablonul corespunzător. Poți încerca să vezi dacă funcționează corect schimbând URL-ul manual în browserul tău.
✅ Ce se întâmplă dacă introduci o cale necunoscută în URL? Cum am putea rezolva acest lucru?
Adăugarea navigației
Următorul pas pentru aplicația noastră este să adăugăm posibilitatea de a naviga între pagini fără a fi nevoie să schimbăm URL-ul manual. Acest lucru implică două lucruri:
- Actualizarea URL-ului curent
- Actualizarea șablonului afișat pe baza noului URL
Am rezolvat deja partea a doua cu funcția updateRoute
, așa că trebuie să ne dăm seama cum să actualizăm URL-ul curent.
Va trebui să folosim JavaScript și, mai exact, history.pushState
, care permite actualizarea URL-ului și crearea unei noi intrări în istoricul de navigare, fără reîncărcarea HTML-ului.
Notă: Deși elementul HTML de ancoră
<a href>
poate fi utilizat singur pentru a crea hyperlinkuri către diferite URL-uri, va face ca browserul să reîncarce HTML-ul implicit. Este necesar să prevenim acest comportament atunci când gestionăm rutarea cu JavaScript personalizat, folosind funcțiapreventDefault()
pe evenimentul de click.
Sarcină
Să creăm o funcție nouă pe care o putem folosi pentru a naviga în aplicația noastră:
function navigate(path) {
window.history.pushState({}, path, path);
updateRoute();
}
Această metodă actualizează mai întâi URL-ul curent pe baza căii date, apoi actualizează șablonul. Proprietatea window.location.origin
returnează root-ul URL-ului, permițându-ne să reconstruim un URL complet dintr-o cale dată.
Acum că avem această funcție, putem rezolva problema pe care o avem dacă o cale nu se potrivește cu nicio rută definită. Vom modifica funcția updateRoute
adăugând un fallback la una dintre rutele existente dacă nu găsim o potrivire.
function updateRoute() {
const path = window.location.pathname;
const route = routes[path];
if (!route) {
return navigate('/login');
}
...
Dacă o rută nu poate fi găsită, acum vom redirecționa către pagina de autentificare.
Acum să creăm o funcție pentru a obține URL-ul atunci când se face click pe un link și pentru a preveni comportamentul implicit al browserului pentru linkuri:
function onLinkClick(event) {
event.preventDefault();
navigate(event.target.href);
}
Să completăm sistemul de navigare adăugând legături pentru Login și Logout în HTML.
<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
...
<a href="/login" onclick="onLinkClick(event)">Logout</a>
Obiectul event
de mai sus capturează evenimentul click
și îl transmite funcției noastre onLinkClick
.
Folosind atributul onclick
, leagă evenimentul click
de codul JavaScript, aici apelul funcției navigate()
.
Încearcă să faci click pe aceste linkuri, ar trebui să poți naviga acum între diferitele ecrane ale aplicației tale.
✅ Metoda history.pushState
face parte din standardul HTML5 și este implementată în toate browserele moderne. Dacă construiești o aplicație web pentru browsere mai vechi, există un truc pe care îl poți folosi în locul acestei API: utilizând un hash (#
) înainte de cale, poți implementa rutarea care funcționează cu navigarea obișnuită prin ancoră și nu reîncarcă pagina, deoarece scopul său era să creeze linkuri interne într-o pagină.
Gestionarea butoanelor de înainte și înapoi ale browserului
Utilizarea history.pushState
creează noi intrări în istoricul de navigare al browserului. Poți verifica acest lucru ținând apăsat butonul înapoi al browserului, ar trebui să afișeze ceva de genul acesta:
Dacă încerci să faci click pe butonul înapoi de câteva ori, vei vedea că URL-ul curent se schimbă și istoricul este actualizat, dar același șablon continuă să fie afișat.
Asta pentru că aplicația nu știe că trebuie să apelăm updateRoute()
de fiecare dată când istoricul se schimbă. Dacă te uiți la documentația history.pushState
, poți vedea că dacă starea se schimbă - adică ne-am mutat la un URL diferit - evenimentul popstate
este declanșat. Vom folosi acest lucru pentru a rezolva problema.
Sarcină
Pentru a ne asigura că șablonul afișat este actualizat atunci când istoricul browserului se schimbă, vom atașa o funcție nouă care apelează updateRoute()
. Vom face acest lucru în partea de jos a fișierului app.js
:
window.onpopstate = () => updateRoute();
updateRoute();
Notă: am folosit o funcție săgeată aici pentru a declara handler-ul evenimentului
popstate
pentru concizie, dar o funcție obișnuită ar funcționa la fel.
Iată un videoclip de recapitulare despre funcțiile săgeată:
🎥 Fă click pe imaginea de mai sus pentru un videoclip despre funcțiile săgeată.
Acum încearcă să folosești butoanele de înainte și înapoi ale browserului și verifică dacă ruta afișată este actualizată corect de această dată.
🚀 Provocare
Adaugă un nou șablon și o rută pentru o a treia pagină care afișează creditele pentru această aplicație.
Chestionar după lecție
Recapitulare și studiu individual
Rutarea este una dintre părțile surprinzător de dificile ale dezvoltării web, mai ales pe măsură ce web-ul trece de la comportamentele de reîmprospătare a paginilor la reîmprospătările aplicațiilor de tip Single Page Application. Citește puțin despre cum serviciul Azure Static Web App gestionează rutarea. Poți explica de ce unele dintre deciziile descrise în acel document sunt necesare?
Temă
Declinarea responsabilității:
Acest document a fost tradus folosind serviciul de traducere AI Co-op Translator. Deși depunem eforturi pentru a asigura acuratețea, vă rugăm să rețineți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa nativă ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm răspunderea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.