アプリのドメイン
ウェブアプリに適用されるミニアプリのプログラミング方法 を示すには、小規模ながら十分なアプリのアイデアが必要でした。 高強度インターバル トレーニング(HIIT) は、高強度の無酸素運動を短時間行うセットと、低強度の回復期間を交互に行う心血管運動戦略です。多くの HIIT トレーニングでは、HIIT タイマーを使用します。たとえば、この 30 分間のオンライン セッション The Body Coach TV YouTube チャンネルなどです。
HIIT Time サンプルアプリ
この章では、ユーザーがさまざまなタイマーを定義して管理できる「HIIT Time」という HIIT タイマーアプリの基本的な例を作成しました。タイマーは常に高強度と低強度のインターバルで構成され、トレーニング セッション用にいずれかを選択できます。 これは、ナビゲーション バー、タブバー、3 つのページを備えたレスポンシブ アプリです。
- ワークアウト: ワークアウト中のアクティブなページ。ユーザーはタイマーのいずれかを選択でき、セット数、アクティブ期間、休息期間の 3 つのプログレス リングが表示されます。
- タイマー: 既存のタイマーを管理し、新しいタイマーを作成できます。
- 設定: 効果音と音声出力を切り替えたり、言語とテーマを選択したりできます。
次のスクリーンショットは、アプリケーションのイメージを示しています。
アプリの構造
前述のように、アプリはナビゲーション バー、タブバー、3 つのページで構成され、グリッドに配置されています。
ナビゲーション バーとタブバーは iframe として実現され、その間に <div> コンテナがあり、ページ用の iframe が 3 つあります。このうち 1 つは常に表示され、タブバーのアクティブな選択に依存します。about:blank を指す最後の iframe は、動的に作成されたアプリ内ページに使用されます。これは、既存のタイマーを変更したり、新しいタイマーを作成したりするために必要です。このパターンをマルチページ シングルページ アプリ(MPSPA)と呼びます。
コンポーネント ベースの lit-html マークアップ
各ページの構造は、lit-html スキャフォールド
として実現されます。
実行時に動的に評価されます。lit-html は、JavaScript 用の効率的で表現力豊かで拡張可能な HTML テンプレート ライブラリです。
HTML
ファイルで直接使用することで、メンタル プログラミング モデルは直接出力指向になります。
プログラマーは最終的な出力のテンプレートを作成し、lit-
html はデータに基づいてギャップを動的に埋め、イベント リスナーをフックします。
このアプリでは、Shoelace's <sl-progress-ring> や、<human-duration> という自己実装のカスタム要素などのサードパーティのカスタム要素を使用しています。
カスタム要素には宣言型
API(プログレス リングの percentage 属性など)があるため、次のリストに示すように、lit-html とうまく連携します。
<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>
プログラミング モデル
各ページには、イベント ハンドラの実装を提供し、各ページのデータを提供することで、lit-html マークアップを埋める対応する Page
クラスがあります。
このクラスは、onShow()、onHide()、onLoad()、onUnload() などのライフサイクル
メソッドもサポートしています。
ページは、ページごとの状態とグローバル状態を共有するために使用されるデータストアにアクセスできます。
すべての文字列は一元的に管理されるため、国際化が組み込まれています。
ルーティングはブラウザによって基本的に無料で処理されます。アプリは
iframe の表示を切り替え、動的に作成されたページではプレースホルダ iframe の src
属性を変更するだけです。
次の例は、動的に作成されたページを閉じるコードを示しています。
import Page from '../page.js';
const page = new Page({
eventHandlers: {
back: (e) => {
e.preventDefault();
window.top.history.back();
},
},
});
スタイル設定
ページのスタイル設定は、独自のスコープ付き CSS ファイルでページごとに行われます。
つまり、他のページとの競合が発生しないため、通常は要素名を直接指定できます。
グローバル
スタイルは各ページに追加されるため、font-family や box-sizing
などの中心的な設定を繰り返し宣言する必要はありません。
テーマとダークモードのオプションもここで定義します。
次のリスティングは、グリッド上にさまざまなフォーム要素を配置する
[設定] ページのルールを示しています。
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;
}
画面の wake lock
ワークアウト中は、画面がオフにならないようにする必要があります。 HIIT Time は、画面の wake lockをサポートするブラウザでこれを実現します。次のスニペットにその方法を示します。
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();
}
});
}
アプリケーションをテストする
HIIT Time アプリケーションは GitHub で入手できます。 新しいウィンドウでデモを再生することも、 モバイルデバイスをシミュレートする以下の iframe 埋め込みで直接再生することもできます。
謝辞
この記事は、 Joe Medley、 Kayce Basques、 Milica Mihajlija、 Alan Kent、 Keith Gu によってレビューされました。