Observer la progression à l’écran
Objectif : Déclencher le calcul et l’affichage de la progression lorsque son panneau entre dans la zone visible, puis actualiser cette progression après les actions de l’utilisateur.
Un panneau placé en bas d’une page peut rester longtemps hors de l’écran. Calculer et actualiser son contenu dès le démarrage n’apporte rien tant que la personne ne le voit pas. Vous allez observer sa visibilité et lancer le premier affichage à son entrée dans la zone visible.
Le HTML du projet contient déjà le point d’ancrage `data-progression` sur le panneau concerné. Vous utiliserez `IntersectionObserver`, une API du navigateur qui signale quand un élément entre dans une zone d’intersection avec la fenêtre, ou en sort. La configuration ci-dessous observe le panneau par rapport à la fenêtre du navigateur et déclenche l’affichage dès qu’une partie de celui-ci devient visible.
Observer le panneau de progression
Ajoutez cette fonction à `js/progression.js`. Elle reçoit une fonction de rappel et lui transmet l’entrée observée quand le panneau devient visible. Après le premier affichage, l’observation est arrêtée : le panneau reste à l’écran et c’est l’application qui déclenche les actualisations suivantes lorsque l’état change.
export function observerProgression(panneau, auPremierAffichage) {
if (!(panneau instanceof Element)) {
throw new TypeError("Le panneau de progression est introuvable.");
}
let affichageDeclenche = false;
const observateur = new IntersectionObserver(function (entrees) {
for (const entree of entrees) {
if (entree.isIntersecting && !affichageDeclenche) {
affichageDeclenche = true;
observateur.unobserve(panneau);
auPremierAffichage();
}
}
}, {
root: null,
threshold: 0.1
});
observateur.observe(panneau);
return observateur;
}Le seuil `0.1` signifie que le rappel peut être déclenché lorsqu’au moins 10 % du panneau intersecte la fenêtre. Le navigateur décide du moment où il signale le changement ; vous n’avez donc pas besoin d’interroger la position du panneau à chaque événement de défilement. Le paramètre `root: null` désigne la fenêtre comme zone de référence.
Relier l’observation à l’état
Dans `js/main.js`, gardez vos imports et votre logique de restauration, de réduction et d’enregistrement des actions établis dans les leçons précédentes. Ajoutez l’import de `observerProgression`, puis préparez une fonction qui met à jour les éléments du panneau. Le calcul reste simple : comptez les tâches terminées, puis attribuez les valeurs correspondantes au texte et à l’élément `progress`.
import { etatInitial } from "./etat.js";
import { reduireEtat } from "./reducteur.js";
import { enregistrerInteractions } from "./dom.js";
import { chargerTaches, enregistrerTaches } from "./persistance.js";
import { observerProgression } from "./progression.js";
let etat = {
...etatInitial,
taches: chargerTaches()
};
const panneauProgression = document.querySelector("[data-progression]");
const elementTerminees = document.querySelector("[data-terminees]");
const elementTotal = document.querySelector("[data-total]");
const barre = document.querySelector("[data-barre]");
function afficherProgression() {
const total = etat.taches.length;
const terminees = etat.taches.filter(function (tache) {
return tache.terminee;
}).length;
elementTerminees.textContent = String(terminees);
elementTotal.textContent = String(total);
barre.max = total;
barre.value = terminees;
barre.textContent = total === 0
? "0%"
: `${Math.round((terminees / total) * 100)}%`;
}
let progressionVisible = false;
observerProgression(panneauProgression, function () {
progressionVisible = true;
afficherProgression();
});
enregistrerInteractions(function (action) {
etat = reduireEtat(etat, action);
enregistrerTaches(etat.taches);
if (progressionVisible) {
afficherProgression();
}
});Ce fichier conserve les responsabilités déjà en place : les interactions produisent des actions, le réducteur fait évoluer l’état et la persistance enregistre les tâches. L’observateur ne modifie pas cet état ; il décide seulement quand lancer le premier affichage. Une fois le panneau visible, chaque action déclenche l’actualisation des nombres et de la barre. Si l’application charge déjà la liste des tâches dans un autre module, conservez ce mécanisme de restauration plutôt que de le dupliquer.
La fonction suppose que chaque tâche possède une propriété booléenne `terminee`, conformément à la forme retenue pour l’état. Avec une liste vide, `max` et `value` valent zéro et le texte affiché reste `0%`. Avec quatre tâches dont deux terminées, le panneau indique « 2 tâche(s) terminée(s) sur 4 » et la barre représente 50 %.
À retenir
- `IntersectionObserver` signale les changements de visibilité sans écouteur de défilement permanent.
- `threshold` règle la proportion visible nécessaire au déclenchement ; `root: null` utilise la fenêtre.
- L’observation différée peut lancer le premier affichage seulement lorsque le panneau devient visible.
- Après ce premier affichage, actualisez la progression en réponse aux actions qui changent l’état.
Dans la prochaine leçon, vous ajouterez la copie d’un résumé des tâches au moyen de l’API Clipboard du navigateur.