Domena aplikacji
Aby pokazać sposób programowania małej aplikacji w przypadku aplikacji internetowej, potrzebowałem pomysłu na małą, ale wystarczająco kompletną aplikację. Intensywny trening interwałowy (HIIT) to strategia ćwiczeń kardio polegająca na naprzemiennym wykonywaniu krótkich okresów intensywnego wysiłku beztlenowego i mniej intensywnych okresów odpoczynku. Wiele treningów HIIT wykorzystuje minutniki HIIT, na przykład tę 30-minutową sesję online z kanału YouTube The Body Coach TV.


Przykładowa aplikacja HIIT Time
Na potrzeby tego rozdziału utworzyłem prosty przykład takiej aplikacji, która nosi trafną nazwę „HIIT Time”. Umożliwia ona użytkownikowi definiowanie różnych liczników czasu i zarządzanie nimi (zawsze obejmują one interwał o wysokiej i niskiej intensywności), a potem wybranie jednego z nich na potrzeby sesji treningowej. Jest to responsywna aplikacja z paskiem nawigacji, paskiem kart i 3 stronami:
- Trening:aktywna strona podczas treningu. Umożliwia użytkownikowi wybranie jednego z zegarów. Zawiera 3 okręgi postępu: liczbę serii, okres aktywny i okres odpoczynku.
- Timery: umożliwia zarządzanie istniejącymi zegarami i tworzenie nowych.
- Ustawienia: umożliwiają przełączanie efektów dźwiękowych i wyświetlania tekstu oraz wybór języka i motywu.
Poniżej znajdziesz zrzuty ekranu przedstawiające aplikację.
Struktura aplikacji
Jak już wspomnieliśmy, aplikacja składa się z paska nawigacyjnego, paska kart i 3 stron ułożonych w siatkową siatkę.
Pasek nawigacyjny i pasek kart są realizowane jako elementy iframe z kontenerem <div>
, pomiędzy którymi znajdują się 3 kolejne elementy iframe dla stron. Jeden z nich jest zawsze widoczny i zależy od aktywnego elementu na pasku kart.
Ostatni tag iframe wskazujący na about:blank
służy do dynamicznego tworzenia stron w aplikacji, które są potrzebne do modyfikowania dotychczasowych zegarów lub tworzenia nowych.
Nazywam ten wzór wielostronicową aplikacją jednostronicową (MPSPA).

znaczniki lit-html oparte na komponentach;
Struktura każdej strony jest realizowana jako szkielet lit-html, który jest dynamicznie oceniany w czasie wykonywania.
Lit-html to wydajna, elastyczna i rozszerzalna biblioteka szablonów HTML do JavaScriptu.
Dzięki temu, że model jest używany bezpośrednio w plikach HTML, jest on bezpośrednio ukierunkowany na dane wyjściowe.
Jako programista piszesz szablon, który będzie wyglądać jak wynik końcowy, a lit-html wypełnia luki dynamicznie na podstawie Twoich danych i podłącza detektory zdarzeń.
Aplikacja korzysta z elementów niestandardowych innych firm, takich jak <sl-progress-ring>
firmy Shoelace lub z elementu niestandardowego o nazwie <human-duration>
, który został zaimplementowany przez użytkownika.
Ponieważ elementy niestandardowe mają interfejs deklaratywny API (np. atrybut percentage
pierścienia postępu),
działają dobrze z lit-html, jak widać na liście poniżej.
<div>
<button class="start" @click="${eventHandlers.start}" type="button">
${strings.START}
</button>
<button class="pause" @click="${eventHandlers.pause}" type="button">
${strings.PAUSE}
</button>
<button class="reset" @click="${eventHandlers.reset}" type="button">
${strings.RESET}
</button>
</div>
<div class="progress-rings">
<sl-progress-ring
class="sets"
percentage="${Math.floor(data.sets/data.activeTimer.sets*100)}"
>
<div class="progress-ring-caption">
<span>${strings.SETS}</span>
<span>${data.sets}</span>
</div>
</sl-progress-ring>
</div>

Model programowania
Każda strona ma odpowiednią klasę Page
, która wypełnia znaczniki znaczników lit-html, zapewniając implementacje elementów obsługi zdarzeń i dane dla każdej strony.
Ta klasa obsługuje też metody cyklu życia, takie jak onShow()
, onHide()
, onLoad()
i onUnload()
.
Strony mają dostęp do magazynu danych, który służy do udostępniania opcjonalnie utrwalonego stanu na stronie i stanu globalnego.
Wszystkie ciągi tekstowe są zarządzane centralnie, więc międzynarodowość jest wbudowana.
Przekierowanie jest obsługiwane przez przeglądarkę praktycznie bezpłatnie, ponieważ aplikacja tylko przełącza widoczność iframe i w przypadku stron tworzonych dynamicznie zmienia atrybut src
iframe zastępczego.
Przykład poniżej pokazuje kod służący do zamykania strony utworzonej dynamicznie.
import Page from '../page.js';
const page = new Page({
eventHandlers: {
back: (e) => {
e.preventDefault();
window.top.history.back();
},
},
});

Styl
Stylowanie stron odbywa się w osobnym pliku CSS.
Oznacza to, że elementy można zwykle adresować bezpośrednio, podając ich nazwy, ponieważ nie dochodzi do kolizji z innymi stronami.
Style globalne są dodawane do każdej strony, więc ustawień centralnych, takich jak font-family
lub box-sizing
, nie trzeba deklarować wielokrotnie.
Tutaj definiowane są też motywy i opcje trybu ciemnego.
Poniżej znajduje się lista reguł dotyczących strony Ustawienia, która zawiera różne elementy formularza w siatce.
main {
max-width: 600px;
}
form {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 0.5rem;
margin-block-end: 1rem;
}
label {
text-align: end;
grid-column: 1 / 2;
}
input,
select {
grid-column: 2 / 3;
}

Blokada wybudzania ekranu
Podczas treningu ekran nie powinien się wyłączać. W przeglądarkach, które to umożliwiają, HIIT Time realizuje to za pomocą blokady ekranu. Poniżej znajdziesz fragment kodu, który to pokazuje.
if ('wakeLock' in navigator) {
const requestWakeLock = async () => {
try {
page.shared.wakeLock = await navigator.wakeLock.request('screen');
page.shared.wakeLock.addEventListener('release', () => {
// Nothing.
});
} catch (err) {
console.error(`${err.name}, ${err.message}`);
}
};
// Request a screen wake lock…
await requestWakeLock();
// …and re-request it when the page becomes visible.
document.addEventListener('visibilitychange', async () => {
if (
page.shared.wakeLock !== null &&
document.visibilityState === 'visible'
) {
await requestWakeLock();
}
});
}
Testowanie aplikacji
Aplikacja HIIT Time jest dostępna na GitHub. Możesz odtworzyć demo w nowym oknie lub wbudowanym iframe poniżej, który symuluje urządzenie mobilne.
Podziękowania
Ten artykuł został sprawdzony przez Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent i Keitha Gu.