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ę. Trening interwałowy o wysokiej intensywności (HIIT) to strategia ćwiczeń sercowo-naczyniowych polegająca na naprzemiennych zestawach krótkich, intensywnych ćwiczeń beztlenowych z mniej intensywnymi okresami regeneracji. Wiele treningów HIIT wykorzystuje minutniki HIIT, na przykład tę 30-minutową sesję online z kanału YouTube The Body Coach TV.
![Sesja treningu HIIT online z zielonym timerem intensywności.](https://web.developers.google.cn/static/articles/mini-apps/mini-app-example-project/image/hiit-training-online-sess-ed5b035be1093.png?authuser=0&hl=pl)
![Sesja online treningu HIIT z czerwonym licznikiem czasu o niskim stopniu intensywności.](https://web.developers.google.cn/static/articles/mini-apps/mini-app-example-project/image/hiit-training-online-sess-a0dd5340756f1.png?authuser=0&hl=pl)
Przykładowa aplikacja HIIT Time
Na potrzeby tego rozdziału utworzyłem prosty przykład takiej aplikacji, która nosi trafną nazwę „HIIT Time”. Pozwala ona użytkownikowi definiować różne timery i nimi zarządzać. Każdy z nich składa się z interwału o wysokiej i niskiej intensywności. Następnie użytkownik może wybrać jeden z nich na potrzeby sesji treningowej. Jest to elastyczna aplikacja z paskiem nawigacyjnym i paskiem kart oraz 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 mowy oraz wybór języka i motywu.
Poniżej znajdziesz zrzuty ekranu przedstawiające aplikację.
Struktura aplikacji
Jak wspomnieliśmy powyżej, aplikacja składa się z paska nawigacyjnego, paska kart i 3 stron rozmieszczonych w siatce.
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 wyboru na pasku kart.
Końcowy element iframe wskazujący about:blank
jest wyświetlany w przypadku dynamicznie tworzonych stron w aplikacji, które są potrzebne do modyfikowania istniejących liczników czasu lub tworzenia nowych.
Nazywamy ten wzorzec wielostronicową aplikacją jednostronicową (MPSPA).
![Widok struktury HTML aplikacji w Narzędziach deweloperskich Chrome, który pokazuje, że składa się ona z 6 ramek iframe: jednej dla paska nawigacyjnego, jednej dla paska kart i 3 ramek zgrupowanych dla każdej strony aplikacji oraz ostatniej ramki iframe jako placeholdera dla stron dynamicznych.](https://web.developers.google.cn/static/articles/mini-apps/mini-app-example-project/image/chrome-devtools-view-the-9da043317ba5b.png?authuser=0&hl=pl)
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 przedstawiający ostateczne dane wyjściowe, a następnie lit-html dynamicznie wypełnia luki na podstawie Twoich danych i łączy 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.
Elementy niestandardowe mają deklaratywny interfejs API (np. atrybut percentage
pierścienia postępu), więc dobrze współdziałają z lit-html, jak widać na poniższej liście.
<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>
![3 przyciski i okrąg postępu.](https://web.developers.google.cn/static/articles/mini-apps/mini-app-example-project/image/three-buttons-a-progress-df2f6a20c093.png?authuser=0&hl=pl)
Model programowania
Każda strona ma odpowiadającą jej klasę Page
, która wypełnia znaczniki znaczników lit-html, zapewniając implementacje 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();
},
},
});
![Strona w aplikacji zrealizowana jako element iframe.](https://web.developers.google.cn/static/articles/mini-apps/mini-app-example-project/image/in-app-page-realized-an-25ec73e15af7f.png?authuser=0&hl=pl)
Styl
Stylowanie stron odbywa się w ramach ich własnych plików 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 centralne ustawienia, takie jak font-family
czy box-sizing
, nie muszą być deklarowane wielokrotnie.
Tutaj możesz też określić motywy i opcje trybu ciemnego.
Poniższa lista zawiera reguły dotyczące strony Ustawienia, na której znajdują się 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;
}
![Strona ustawień aplikacji HIIT Time przedstawiająca formularz w układzie siatki.](https://web.developers.google.cn/static/articles/mini-apps/mini-app-example-project/image/hiit-app-preferences-pag-3d83359174159.png?authuser=0&hl=pl)
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 GitHubzie. Możesz wypróbować demo w nowym oknie lub w ramce iframe umieszczonej poniżej, która symuluje urządzenie mobilne.
Podziękowania
Ten artykuł został sprawdzony przez Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent i Keitha Gu.