Appliquer les principes de programmation des mini-applications à un exemple de projet

Domaine de l'application

Pour montrer la méthode de programmation en miniature appliquée à une application Web, il me fallait une idée d'application courte, mais suffisamment complète. L'entraînement fractionné haute intensité (HIIT) est une stratégie cardiovasculaire qui consiste à alterner des séries courtes d'exercices anaérobies intenses avec des périodes de récupération moins intenses. De nombreux entraînements HIIT utilisent des minuteurs HIIT, comme cette session en ligne de 30 minutes de la chaîne YouTube The Body Coach TV.

Séance d'entraînement HIIT en ligne avec minuteur vert haute intensité.
Période active.
Séance d'entraînement HIIT en ligne avec minuteur rouge faible intensité.
Période de repos.

Exemple d'application pour l'entraînement par intervalles haute intensité

Pour ce chapitre, j'ai créé un exemple élémentaire d'une telle application de minuteur HIIT, nommée "temps HIIT", qui permet à l'utilisateur de définir et de gérer différents minuteurs, toujours composés d'un intervalle d'intensité élevée et d'un intervalle faible, puis de sélectionner l'un d'entre eux pour une session d'entraînement. Il s'agit d'une application responsive avec une barre de navigation, une barre d'onglets et trois pages:

  • Entraînement:page active pendant un entraînement. Elle permet à l'utilisateur de sélectionner l'un des minuteurs et présente trois anneaux de progression: le nombre d'ensembles, la période active et la période au repos.
  • Minuteurs:permet de gérer les minuteurs existants et d'autoriser l'utilisateur à en créer d'autres.
  • Préférences:permet d'activer ou de désactiver les effets sonores et la sortie vocale, et de sélectionner une langue et un thème.

Les captures d'écran suivantes donnent une idée de l'application.

Exemple d'application EIHI en mode Portrait
Onglet "Entraînement" lors d'un entraînement par intervalles haute intensité en mode Portrait.
Exemple d'application de temps EIHI en mode Paysage
Onglet "Entraînement" pour l'entraînement par intervalles haute intensité en mode Paysage.
Exemple d'application EIHI montrant la gestion d'un minuteur.
Gestion du minuteur HIIT.

Structure de l'application

Comme indiqué ci-dessus, l'application se compose d'une barre de navigation, d'une barre d'onglets et de trois pages disposées sous forme de grille. La barre de navigation et la barre d'onglets sont réalisées comme des iFrames comprenant un conteneur <div> et trois iFrames supplémentaires pour les pages, dont un est toujours visible et dépend de la sélection active dans la barre d'onglets. Un iFrame final pointant vers about:blank diffuse les pages intégrées à l'application créées dynamiquement, nécessaires pour modifier des minuteurs existants ou en créer de nouveaux. J'appelle ce modèle une application monopage (MPSPA) à plusieurs pages.

Vue de la structure HTML de l&#39;application dans les outils pour les développeurs Chrome, montrant qu&#39;elle se compose de six iFrames: un pour la barre de navigation, un pour la barre d&#39;onglets et trois groupés pour chaque page de l&#39;application, avec un iFrame final réservé aux pages dynamiques.
L'application se compose de six iFrame.

Balisage lit-html basé sur des composants

La structure de chaque page est réalisée sous la forme d'une structure lit-html évaluée de manière dynamique au moment de l'exécution. Pour un arrière-plan avec lit-html, il s'agit d'une bibliothèque de modèles HTML efficace, expressive et extensible pour JavaScript. En l'utilisant directement dans les fichiers HTML, le modèle de programmation mentale est directement orienté sortie. En tant que programmeur, vous écrivez un modèle de la sortie finale, puis lit-html remplit dynamiquement les lacunes en fonction de vos données et connecte les écouteurs d'événements. L'application utilise des éléments personnalisés tiers tels que le <sl-progress-ring> de Shoelace ou un élément personnalisé que l'utilisateur a conçu automatiquement, appelé <human-duration>. Étant donné que les éléments personnalisés ont une API déclarative (par exemple, l'attribut percentage de l'anneau de progression), ils fonctionnent bien avec lit-html, comme vous pouvez le voir dans la liste ci-dessous.

<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>
Trois boutons et un anneau de progression.
Section affichée de la page correspondant au balisage ci-dessus.

Modèle de programmation

Chaque page possède une classe Page correspondante qui remplit le balisage lit-html avec de la vie en fournissant des implémentations des gestionnaires d'événements et des données pour chaque page. Cette classe est également compatible avec les méthodes de cycle de vie telles que onShow(), onHide(), onLoad() et onUnload(). Les pages ont accès à un data store qui sert à partager l'état de chaque page et l'état global (facultatif). Toutes les chaînes étant gérées de manière centralisée, l'internationalisation est intégrée. Le routage est géré sans frais par le navigateur, car l'application se contente d'activer/de désactiver la visibilité de l'iFrame et, pour les pages créées dynamiquement, modifiez l'attribut src de l'iFrame d'espace réservé. L'exemple ci-dessous présente le code permettant de fermer une page créée dynamiquement.

import Page from '../page.js';

const page = new Page({
  eventHandlers: {
    back: (e) => {
      e.preventDefault();
      window.top.history.back();
    },
  },
});
Page intégrée à l&#39;application créée sous la forme d&#39;un iFrame.
La navigation s'effectue de l'iFrame à l'iFrame.

Attribuer un style

Le style des pages est appliqué à chaque page dans son propre fichier CSS limité. Cela signifie que les éléments peuvent généralement être simplement adressés directement par leur nom d'élément, car aucun conflit avec d'autres pages ne peut se produire. Des styles globaux sont ajoutés à chaque page. Ainsi, les paramètres centraux tels que font-family ou box-sizing n'ont pas besoin d'être déclarés à plusieurs reprises. Les thèmes et les options du mode sombre sont également définis. La liste ci-dessous présente les règles de la page "Préférences", qui présentent les différents éléments du formulaire sur une grille.

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;
}
Page des préférences de l&#39;application HIIT Time affichant un formulaire sous forme de grille.
Chaque page a son propre univers. Le style est appliqué directement aux noms des éléments.

Activation du verrouillage de l'écran

Pendant un entraînement, l'écran ne doit pas s'éteindre. Sur les navigateurs compatibles, l'option HIIT Time le détecte via un wakelock de l'écran. L'extrait ci-dessous montre comment procéder.

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();
    }
  });
}

Tester l'application

L'application de temps HIIT est disponible sur GitHub. Vous pouvez jouer avec la démonstration dans une nouvelle fenêtre ou directement dans l'iFrame intégré ci-dessous, qui simule un appareil mobile.

Remerciements

Cet article a été lu par Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent et Keith Gu.