You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
15 KiB
322 lines
15 KiB
<!--
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
{
|
|
"original_hash": "8a07db14e75ac62f013b7de5df05981d",
|
|
"translation_date": "2025-08-29T10:46:31+00:00",
|
|
"source_file": "7-bank-project/1-template-route/README.md",
|
|
"language_code": "cs"
|
|
}
|
|
-->
|
|
# Vytvoření bankovní aplikace, část 1: HTML šablony a trasy ve webové aplikaci
|
|
|
|
## Kvíz před lekcí
|
|
|
|
[Kvíz před lekcí](https://ff-quizzes.netlify.app/web/quiz/41)
|
|
|
|
### Úvod
|
|
|
|
Od vzniku JavaScriptu v prohlížečích se webové stránky stávají interaktivnějšími a složitějšími než kdy dříve. Webové technologie se nyní běžně používají k vytváření plně funkčních aplikací, které běží přímo v prohlížeči, a nazýváme je [webové aplikace](https://en.wikipedia.org/wiki/Web_application). Protože jsou webové aplikace vysoce interaktivní, uživatelé nechtějí čekat na úplné načtení stránky pokaždé, když provedou nějakou akci. Proto se používá JavaScript k přímé aktualizaci HTML pomocí DOM, aby se zajistil plynulejší uživatelský zážitek.
|
|
|
|
V této lekci položíme základy pro vytvoření bankovní webové aplikace, přičemž použijeme HTML šablony k vytvoření více obrazovek, které lze zobrazit a aktualizovat bez nutnosti znovu načítat celou HTML stránku.
|
|
|
|
### Předpoklady
|
|
|
|
Pro testování webové aplikace, kterou v této lekci vytvoříme, potřebujete lokální webový server. Pokud ho nemáte, můžete si nainstalovat [Node.js](https://nodejs.org) a použít příkaz `npx lite-server` ve složce svého projektu. Tím vytvoříte lokální webový server a otevřete svou aplikaci v prohlížeči.
|
|
|
|
### Příprava
|
|
|
|
Na svém počítači vytvořte složku nazvanou `bank` a uvnitř ní soubor `index.html`. Začneme s tímto HTML [základem](https://en.wikipedia.org/wiki/Boilerplate_code):
|
|
|
|
```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>
|
|
```
|
|
|
|
---
|
|
|
|
## HTML šablony
|
|
|
|
Pokud chcete vytvořit více obrazovek pro webovou stránku, jedním řešením by bylo vytvořit jeden HTML soubor pro každou obrazovku, kterou chcete zobrazit. Toto řešení však přináší určité nevýhody:
|
|
|
|
- Při přepínání obrazovek musíte znovu načíst celé HTML, což může být pomalé.
|
|
- Je obtížné sdílet data mezi různými obrazovkami.
|
|
|
|
Dalším přístupem je mít pouze jeden HTML soubor a definovat více [HTML šablon](https://developer.mozilla.org/docs/Web/HTML/Element/template) pomocí elementu `<template>`. Šablona je znovupoužitelný HTML blok, který není prohlížečem zobrazen a musí být instancován za běhu pomocí JavaScriptu.
|
|
|
|
### Úkol
|
|
|
|
Vytvoříme bankovní aplikaci se dvěma obrazovkami: přihlašovací stránkou a dashboardem. Nejprve přidáme do těla HTML prvek zástupce, který použijeme k instancování různých obrazovek naší aplikace:
|
|
|
|
```html
|
|
<div id="app">Loading...</div>
|
|
```
|
|
|
|
Dáváme mu atribut `id`, aby bylo později snazší ho najít pomocí JavaScriptu.
|
|
|
|
> Tip: protože obsah tohoto prvku bude nahrazen, můžeme do něj vložit zprávu o načítání nebo indikátor, který se zobrazí, zatímco se aplikace načítá.
|
|
|
|
Dále přidáme pod tento prvek HTML šablonu pro přihlašovací stránku. Prozatím do ní vložíme pouze nadpis a sekci obsahující odkaz, který použijeme k navigaci.
|
|
|
|
```html
|
|
<template id="login">
|
|
<h1>Bank App</h1>
|
|
<section>
|
|
<a href="/dashboard">Login</a>
|
|
</section>
|
|
</template>
|
|
```
|
|
|
|
Poté přidáme další HTML šablonu pro stránku dashboardu. Tato stránka bude obsahovat různé sekce:
|
|
|
|
- Hlavičku s nadpisem a odkazem pro odhlášení
|
|
- Aktuální zůstatek na bankovním účtu
|
|
- Seznam transakcí, zobrazený v tabulce
|
|
|
|
```html
|
|
<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>
|
|
```
|
|
|
|
> Tip: při vytváření HTML šablon, pokud chcete vidět, jak budou vypadat, můžete zakomentovat řádky `<template>` a `</template>` tím, že je obklopíte `<!-- -->`.
|
|
|
|
✅ Proč myslíte, že používáme atributy `id` na šablonách? Mohli bychom použít něco jiného, například třídy?
|
|
|
|
## Zobrazení šablon pomocí JavaScriptu
|
|
|
|
Pokud zkusíte aktuální HTML soubor v prohlížeči, uvidíte, že se zasekne na zobrazení `Loading...`. To je proto, že musíme přidat nějaký JavaScriptový kód, který instancuje a zobrazí HTML šablony.
|
|
|
|
Instancování šablony se obvykle provádí ve 3 krocích:
|
|
|
|
1. Získání elementu šablony v DOM, například pomocí [`document.getElementById`](https://developer.mozilla.org/docs/Web/API/Document/getElementById).
|
|
2. Klonování elementu šablony pomocí [`cloneNode`](https://developer.mozilla.org/docs/Web/API/Node/cloneNode).
|
|
3. Připojení k DOM pod viditelný prvek, například pomocí [`appendChild`](https://developer.mozilla.org/docs/Web/API/Node/appendChild).
|
|
|
|
✅ Proč musíme šablonu klonovat, než ji připojíme k DOM? Co si myslíte, že by se stalo, kdybychom tento krok přeskočili?
|
|
|
|
### Úkol
|
|
|
|
Vytvořte nový soubor nazvaný `app.js` ve složce svého projektu a importujte tento soubor do sekce `<head>` svého HTML:
|
|
|
|
```html
|
|
<script src="app.js" defer></script>
|
|
```
|
|
|
|
Nyní v `app.js` vytvoříme novou funkci `updateRoute`:
|
|
|
|
```js
|
|
function updateRoute(templateId) {
|
|
const template = document.getElementById(templateId);
|
|
const view = template.content.cloneNode(true);
|
|
const app = document.getElementById('app');
|
|
app.innerHTML = '';
|
|
app.appendChild(view);
|
|
}
|
|
```
|
|
|
|
To, co zde děláme, jsou přesně 3 kroky popsané výše. Instancujeme šablonu s `id` `templateId` a vložíme její klonovaný obsah do našeho zástupce aplikace. Všimněte si, že musíme použít `cloneNode(true)`, abychom zkopírovali celý podstrom šablony.
|
|
|
|
Nyní zavolejte tuto funkci s jednou ze šablon a podívejte se na výsledek.
|
|
|
|
```js
|
|
updateRoute('login');
|
|
```
|
|
|
|
✅ Jaký je účel tohoto kódu `app.innerHTML = '';`? Co se stane bez něj?
|
|
|
|
## Vytváření tras
|
|
|
|
Když mluvíme o webové aplikaci, nazýváme *trasování* záměr mapovat **URL** na konkrétní obrazovky, které by měly být zobrazeny. Na webové stránce s více HTML soubory se to děje automaticky, protože cesty k souborům se odrážejí v URL. Například s těmito soubory ve složce vašeho projektu:
|
|
|
|
```
|
|
mywebsite/index.html
|
|
mywebsite/login.html
|
|
mywebsite/admin/index.html
|
|
```
|
|
|
|
Pokud vytvoříte webový server s `mywebsite` jako kořen, mapování URL bude:
|
|
|
|
```
|
|
https://site.com --> mywebsite/index.html
|
|
https://site.com/login.html --> mywebsite/login.html
|
|
https://site.com/admin/ --> mywebsite/admin/index.html
|
|
```
|
|
|
|
Nicméně pro naši webovou aplikaci používáme jeden HTML soubor obsahující všechny obrazovky, takže nám toto výchozí chování nepomůže. Musíme tuto mapu vytvořit ručně a aktualizovat zobrazenou šablonu pomocí JavaScriptu.
|
|
|
|
### Úkol
|
|
|
|
Použijeme jednoduchý objekt k implementaci [mapy](https://en.wikipedia.org/wiki/Associative_array) mezi cestami URL a našimi šablonami. Přidejte tento objekt na začátek svého souboru `app.js`.
|
|
|
|
```js
|
|
const routes = {
|
|
'/login': { templateId: 'login' },
|
|
'/dashboard': { templateId: 'dashboard' },
|
|
};
|
|
```
|
|
|
|
Nyní trochu upravíme funkci `updateRoute`. Místo toho, abychom přímo předávali `templateId` jako argument, chceme ho získat nejprve pohledem na aktuální URL a poté použít naši mapu k získání odpovídající hodnoty `templateId`. Můžeme použít [`window.location.pathname`](https://developer.mozilla.org/docs/Web/API/Location/pathname) k získání pouze části cesty z URL.
|
|
|
|
```js
|
|
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);
|
|
}
|
|
```
|
|
|
|
Zde jsme mapovali trasy, které jsme deklarovali, na odpovídající šablonu. Můžete vyzkoušet, že to funguje správně, změnou URL ručně ve svém prohlížeči.
|
|
|
|
✅ Co se stane, když zadáte neznámou cestu do URL? Jak bychom to mohli vyřešit?
|
|
|
|
## Přidání navigace
|
|
|
|
Dalším krokem pro naši aplikaci je přidání možnosti navigace mezi stránkami bez nutnosti ručně měnit URL. To zahrnuje dvě věci:
|
|
|
|
1. Aktualizaci aktuálního URL
|
|
2. Aktualizaci zobrazené šablony na základě nového URL
|
|
|
|
Druhou část jsme již vyřešili pomocí funkce `updateRoute`, takže musíme zjistit, jak aktualizovat aktuální URL.
|
|
|
|
Budeme muset použít JavaScript a konkrétně [`history.pushState`](https://developer.mozilla.org/docs/Web/API/History/pushState), který umožňuje aktualizovat URL a vytvořit nový záznam v historii prohlížení, aniž by se znovu načítalo HTML.
|
|
|
|
> Poznámka: Zatímco HTML prvek kotvy [`<a href>`](https://developer.mozilla.org/docs/Web/HTML/Element/a) může být použit samostatně k vytvoření hypertextových odkazů na různé URL, ve výchozím nastavení způsobí, že prohlížeč znovu načte HTML. Je nutné tomuto chování zabránit při manipulaci s trasováním pomocí vlastního JavaScriptu, použitím funkce preventDefault() na události kliknutí.
|
|
|
|
### Úkol
|
|
|
|
Vytvořme novou funkci, kterou můžeme použít k navigaci v naší aplikaci:
|
|
|
|
```js
|
|
function navigate(path) {
|
|
window.history.pushState({}, path, path);
|
|
updateRoute();
|
|
}
|
|
```
|
|
|
|
Tato metoda nejprve aktualizuje aktuální URL na základě zadané cesty a poté aktualizuje šablonu. Vlastnost `window.location.origin` vrací kořen URL, což nám umožňuje rekonstruovat kompletní URL ze zadané cesty.
|
|
|
|
Nyní, když máme tuto funkci, můžeme se postarat o problém, který máme, pokud cesta neodpovídá žádné definované trase. Upravením funkce `updateRoute` přidáme záložní trasu na jednu z existujících tras, pokud nemůžeme najít shodu.
|
|
|
|
```js
|
|
function updateRoute() {
|
|
const path = window.location.pathname;
|
|
const route = routes[path];
|
|
|
|
if (!route) {
|
|
return navigate('/login');
|
|
}
|
|
|
|
...
|
|
```
|
|
|
|
Pokud nelze najít trasu, nyní přesměrujeme na stránku `login`.
|
|
|
|
Nyní vytvořme funkci pro získání URL při kliknutí na odkaz a zabránění výchozímu chování prohlížeče při kliknutí na odkaz:
|
|
|
|
```js
|
|
function onLinkClick(event) {
|
|
event.preventDefault();
|
|
navigate(event.target.href);
|
|
}
|
|
```
|
|
|
|
Dokončeme navigační systém přidáním vazeb na naše odkazy *Login* a *Logout* v HTML.
|
|
|
|
```html
|
|
<a href="/dashboard" onclick="onLinkClick(event)">Login</a>
|
|
...
|
|
<a href="/login" onclick="onLinkClick(event)">Logout</a>
|
|
```
|
|
|
|
Objekt `event` výše zachytí událost `click` a předá ji naší funkci `onLinkClick`.
|
|
|
|
Pomocí atributu [`onclick`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onclick) připojte událost `click` k JavaScriptovému kódu, zde volání funkce `navigate()`.
|
|
|
|
Zkuste kliknout na tyto odkazy, nyní byste měli být schopni navigovat mezi různými obrazovkami své aplikace.
|
|
|
|
✅ Metoda `history.pushState` je součástí standardu HTML5 a je implementována [ve všech moderních prohlížečích](https://caniuse.com/?search=pushState). Pokud vytváříte webovou aplikaci pro starší prohlížeče, existuje trik, který můžete použít místo této API: použití [hash (`#`)](https://en.wikipedia.org/wiki/URI_fragment) před cestou vám umožní implementovat trasování, které funguje s běžnou navigací kotvy a nenačítá stránku znovu, protože jeho účelem bylo vytvořit interní odkazy na stránce.
|
|
|
|
## Řešení tlačítek zpět a vpřed v prohlížeči
|
|
|
|
Použití `history.pushState` vytváří nové záznamy v historii navigace prohlížeče. Můžete to zkontrolovat podržením *tlačítka zpět* svého prohlížeče, mělo by zobrazit něco jako toto:
|
|
|
|

|
|
|
|
Pokud zkusíte několikrát kliknout na tlačítko zpět, uvidíte, že se aktuální URL mění a historie se aktualizuje, ale stále se zobrazuje stejná šablona.
|
|
|
|
To je proto, že aplikace neví, že je potřeba zavolat `updateRoute()` pokaždé, když se historie změní. Pokud se podíváte na [dokumentaci `history.pushState`](https://developer.mozilla.org/docs/Web/API/History/pushState), můžete vidět, že pokud se stav změní - což znamená, že jsme se přesunuli na jiné URL - je spuštěna událost [`popstate`](https://developer.mozilla.org/docs/Web/API/Window/popstate_event). Použijeme to k vyřešení tohoto problému.
|
|
|
|
### Úkol
|
|
|
|
Abychom zajistili, že zobrazená šablona bude aktualizována, když se historie prohlížeče změní, připojíme novou funkci, která volá `updateRoute()`. Uděláme to na konci našeho souboru `app.js`:
|
|
|
|
```js
|
|
window.onpopstate = () => updateRoute();
|
|
updateRoute();
|
|
```
|
|
|
|
> Poznámka: zde jsme použili [arrow function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions) k deklaraci našeho obslužného programu události `popstate` pro stručnost, ale běžná funkce by fungovala stejně.
|
|
|
|
Zde je video o arrow funkcích:
|
|
|
|
[](https://youtube.com/watch?v=OP6eEbOj2sc "Arrow Functions")
|
|
|
|
> 🎥 Klikněte na obrázek výše pro video o arrow funkcích.
|
|
|
|
Nyní zkuste použít tlačítka zpět a vpřed svého prohlížeče a zkontrolujte, že zobrazená trasa je tentokrát správně aktualizována.
|
|
|
|
---
|
|
|
|
## 🚀 Výzva
|
|
|
|
Přidejte novou šablonu a trasu pro třetí stránku, která zobrazuje kredity této aplikace.
|
|
|
|
## Kvíz po lekci
|
|
|
|
[Kvíz po lekci](https://ff-quizzes.netlify.app/web/quiz/42)
|
|
|
|
## Přehled a samostudium
|
|
|
|
Trasování je jednou z překvapivě složitých částí vývoje webu, zejména když se web přesouvá od chování při obnovování stránky k obnovování stránky v aplikacích typu Single Page Application. Přečtěte si něco o [tom, jak služba Azure Static Web App](https://docs.microsoft.com/azure/static-web-apps/routes/?WT.mc_id=academic-77807-sagibbon) řeší trasování. Dokážete vysvětlit, proč jsou některá rozhodnutí popsaná v tomto dokumentu nezbytná?
|
|
|
|
## Zadání
|
|
|
|
[Zlepšete trasování](assignment.md)
|
|
|
|
---
|
|
|
|
**Prohlášení**:
|
|
Tento dokument byl přeložen pomocí služby pro automatický překlad [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatické překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za autoritativní zdroj. Pro důležité informace doporučujeme profesionální lidský překlad. Neodpovídáme za žádné nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu. |