Tuto JS niveau 4 contact: createElement/append, fetch+async/await+JSON, setInterval, evenements clavier
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
# 🚀 Niveau 4 — DOM propre, données distantes & temps réel
|
||||
|
||||
Salut Mélissa ! 👋
|
||||
|
||||
Suite logique de ce que tu sais déjà faire (tableaux, boucles, `localStorage`, `classList`, événements…). Quatre modules, du plus simple au plus costaud. Comme d'habitude : un exo à la fois, et **✅ teste** avant de passer au suivant.
|
||||
|
||||
| Module | Notion nouvelle | Exos |
|
||||
|---|---|---|
|
||||
| **A. Construire le DOM proprement** | `createElement` / `append` (au lieu de `innerHTML`) | 1 → 2 |
|
||||
| **B. Aller chercher des données ailleurs** | `fetch`, `async`/`await`, JSON | 3 → 5 |
|
||||
| **C. Le temps réel** | `setInterval` | 6 → 7 |
|
||||
| **D. Le clavier** | événements clavier (`keydown`, `event.key`) | 8 |
|
||||
|
||||
---
|
||||
|
||||
# 🧱 Module A — Construire le HTML sans `innerHTML`
|
||||
|
||||
Pour ton tableau d'équipe, tu utilises `corps.innerHTML = lignes`. Ça marche très bien pour **tes** données. Mais `innerHTML` a deux limites :
|
||||
- si tu y mets du texte tapé par un **inconnu**, il peut injecter du code (faille de sécurité dite *XSS*) ;
|
||||
- ça remplace **tout** d'un coup, difficile de modifier une seule ligne ensuite.
|
||||
|
||||
La méthode « propre » consiste à fabriquer chaque élément **un par un**.
|
||||
|
||||
## 🧩 La notion : `createElement` + `textContent` + `append`
|
||||
|
||||
```js
|
||||
const ligne = document.createElement("tr"); // on crée une balise <tr> (vide, pas encore dans la page)
|
||||
|
||||
const caseNom = document.createElement("td");
|
||||
caseNom.textContent = "Mélissa"; // textContent = du texte pur, jamais interprété comme du HTML
|
||||
|
||||
ligne.append(caseNom); // on range la <td> dans la <tr>
|
||||
```
|
||||
|
||||
> 🔎 `createElement` fabrique l'élément **en mémoire** ; il n'apparaît à l'écran qu'une fois **rattaché** à la page avec `append`. `textContent` (et non `innerHTML`) garantit que le contenu reste du **texte**, même si quelqu'un tape `<script>`.
|
||||
|
||||
## 🧪 Exo 1 — Réécrire une ligne du tableau « proprement »
|
||||
|
||||
Dans `equipe.js`, écris une fonction qui fabrique **une** ligne à partir d'un membre :
|
||||
|
||||
```js
|
||||
function creerLigne(membre) {
|
||||
const tr = document.createElement("tr");
|
||||
|
||||
const tdNom = document.createElement("td");
|
||||
tdNom.textContent = membre.nom;
|
||||
|
||||
const tdJob = document.createElement("td");
|
||||
tdJob.textContent = membre.job;
|
||||
|
||||
const tdPartie = document.createElement("td");
|
||||
tdPartie.textContent = membre.partie;
|
||||
|
||||
tr.append(tdNom, tdJob, tdPartie); // append accepte plusieurs éléments d'un coup
|
||||
return tr;
|
||||
}
|
||||
```
|
||||
|
||||
## 🧪 Exo 2 — Remplir le tableau avec cette fonction
|
||||
|
||||
```js
|
||||
const corps = document.getElementById("corps_equipe");
|
||||
|
||||
corps.innerHTML = ""; // on vide d'abord
|
||||
for (const membre of equipe) {
|
||||
corps.append(creerLigne(membre)); // on ajoute chaque ligne fabriquée
|
||||
}
|
||||
```
|
||||
|
||||
**✅ Teste :** le tableau s'affiche comme avant. La différence est invisible à l'écran, mais ton code est maintenant plus sûr et chaque ligne est un vrai objet manipulable.
|
||||
|
||||
> 💡 **À retenir :** `innerHTML` = rapide, pour **tes** données fixes. `createElement` + `textContent` = la méthode propre, surtout dès qu'il y a du contenu venant de l'**utilisateur**.
|
||||
|
||||
---
|
||||
|
||||
# 🌐 Module B — Aller chercher des données ailleurs (`fetch`)
|
||||
|
||||
Jusqu'ici tes données (`equipe`) sont **écrites dans le code**. Dans la vraie vie, elles arrivent **d'un serveur**, sous forme de **JSON** (un format texte très proche des objets/tableaux que tu connais déjà).
|
||||
|
||||
## ⚠️ À lire avant de commencer : il faut un petit serveur
|
||||
|
||||
`fetch` **ne fonctionne pas** si tu ouvres ta page en double-cliquant (adresse en `file://`). Il faut servir le dossier. Dans un terminal, place-toi dans le dossier du projet et lance :
|
||||
|
||||
```bash
|
||||
python3 -m http.server 8000
|
||||
```
|
||||
|
||||
Puis ouvre **http://localhost:8000/pages/contact.html** dans le navigateur. (C'est exactement ce que fait un vrai site : un serveur qui envoie les fichiers.)
|
||||
|
||||
## 🧪 Exo 3 — Créer un fichier de données JSON
|
||||
|
||||
Crée `vehicules.json` à la racine du projet :
|
||||
|
||||
```json
|
||||
[
|
||||
{ "modele": "Renault Kangoo", "immatriculation": "AB-123-CD", "km": 45200 },
|
||||
{ "modele": "Peugeot Partner", "immatriculation": "EF-456-GH", "km": 78900 },
|
||||
{ "modele": "Citroën Berlingo", "immatriculation": "IJ-789-KL", "km": 12300 }
|
||||
]
|
||||
```
|
||||
|
||||
> 🔎 Le JSON ressemble à un tableau d'objets JS, avec **deux règles strictes** : toutes les clés sont **entre guillemets doubles**, et **pas de virgule** après le dernier élément. Une erreur ici et tout casse — colle-le dans un validateur si besoin.
|
||||
|
||||
## 🧪 Exo 4 — Récupérer ce fichier avec `fetch`
|
||||
|
||||
> 🆕 Nouvelles notions : `fetch`, `async`/`await`. `fetch` va chercher un fichier/des données **sur le réseau** ; comme ça prend un peu de temps, on **attend** la réponse avec `await`.
|
||||
|
||||
Dans un nouveau fichier `flotte.js` (branché dans la page) :
|
||||
|
||||
```js
|
||||
async function chargerFlotte() {
|
||||
const reponse = await fetch("../vehicules.json"); // on demande le fichier
|
||||
const vehicules = await reponse.json(); // on le transforme en tableau JS
|
||||
console.log(vehicules); // pour vérifier
|
||||
}
|
||||
|
||||
chargerFlotte();
|
||||
```
|
||||
|
||||
**✅ Teste :** via http://localhost:8000/…, ouvre la Console → tu dois voir ton tableau de 3 véhicules. Si tu vois une erreur, relis la partie « petit serveur » ci-dessus.
|
||||
|
||||
> 🧩 **À retenir :**
|
||||
> - `async` devant une fonction = « cette fonction contient de l'attente ».
|
||||
> - `await` = « attends que ce soit prêt avant de continuer ».
|
||||
> - `fetch(...)` rapporte une **réponse**, et `reponse.json()` la transforme en données JS utilisables.
|
||||
|
||||
## 🧪 Exo 5 — Afficher la flotte + gérer les erreurs
|
||||
|
||||
Ajoute un tableau dans le HTML :
|
||||
|
||||
```html
|
||||
<h3>Notre flotte</h3>
|
||||
<p id="message_flotte">Chargement…</p>
|
||||
<table border="1"><tbody id="corps_flotte"></tbody></table>
|
||||
```
|
||||
|
||||
Puis complète `flotte.js` :
|
||||
|
||||
```js
|
||||
async function chargerFlotte() {
|
||||
const message = document.getElementById("message_flotte");
|
||||
const corps = document.getElementById("corps_flotte");
|
||||
|
||||
try {
|
||||
const reponse = await fetch("../vehicules.json");
|
||||
const vehicules = await reponse.json();
|
||||
|
||||
message.textContent = vehicules.length + " véhicules :";
|
||||
for (const v of vehicules) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.textContent = `${v.modele} — ${v.immatriculation} — ${v.km} km`;
|
||||
corps.append(tr);
|
||||
}
|
||||
} catch (erreur) {
|
||||
message.textContent = "Impossible de charger la flotte 😕";
|
||||
console.error(erreur);
|
||||
}
|
||||
}
|
||||
|
||||
chargerFlotte();
|
||||
```
|
||||
|
||||
**✅ Teste :** la liste des véhicules s'affiche. Renomme exprès `vehicules.json` en `vehicule.json` (faute) et recharge → tu dois voir le message d'erreur au lieu d'un plantage.
|
||||
|
||||
> 🧩 **À retenir :** `try { … } catch (erreur) { … }` = « **essaie** ce code ; **si** ça rate, fais ça plutôt ». Indispensable avec le réseau, où ça peut toujours échouer (pas de connexion, fichier absent…).
|
||||
|
||||
---
|
||||
|
||||
# ⏱️ Module C — Le temps réel avec `setInterval`
|
||||
|
||||
## 🧪 Exo 6 — Une horloge dans le pied de page
|
||||
|
||||
> 🆕 Nouvelle notion : `setInterval(fonction, durée)` répète une action toutes les *durée* millisecondes.
|
||||
|
||||
```html
|
||||
<span id="horloge"></span>
|
||||
```
|
||||
|
||||
```js
|
||||
const horloge = document.getElementById("horloge");
|
||||
|
||||
function afficherHeure() {
|
||||
const maintenant = new Date();
|
||||
horloge.textContent = maintenant.toLocaleTimeString(); // ex. "14:05:32"
|
||||
}
|
||||
|
||||
afficherHeure(); // une fois tout de suite
|
||||
setInterval(afficherHeure, 1000); // puis toutes les 1000 ms = 1 seconde
|
||||
```
|
||||
|
||||
**✅ Teste :** l'heure s'affiche et **avance toute seule** chaque seconde.
|
||||
|
||||
> 🔎 `1000` est en **millisecondes** (1 s). `setInterval` ne s'arrête jamais tout seul ; pour le stopper un jour, on garde son résultat (`const id = setInterval(...)`) et on fait `clearInterval(id)`.
|
||||
|
||||
## 🧪 Exo 7 — Mettre à jour le badge « Ouvert / Fermé » en direct
|
||||
|
||||
Ton badge horaires est calculé **une seule fois** au chargement. Range ce calcul dans une fonction `rafraichirBadge()` puis appelle-la dans ton `setInterval` (par exemple toutes les 60 s). Ainsi, si la page reste ouverte à 18h pile, le badge passera tout seul à « Fermé ».
|
||||
|
||||
**✅ Teste :** pour vérifier sans attendre, mets temporairement l'intervalle à `1000` et change les heures d'ouverture autour de l'heure actuelle.
|
||||
|
||||
---
|
||||
|
||||
# ⌨️ Module D — Réagir au clavier
|
||||
|
||||
## 🧪 Exo 8 — Envoyer avec Ctrl+Entrée, effacer avec Échap
|
||||
|
||||
> 🆕 Nouvelle notion : l'événement `keydown` et la propriété `event.key`.
|
||||
|
||||
```js
|
||||
zoneMessage.addEventListener("keydown", function (event) {
|
||||
// Ctrl + Entrée → on déclenche l'envoi du formulaire
|
||||
if (event.key === "Enter" && event.ctrlKey) {
|
||||
formulaire.requestSubmit(); // comme cliquer sur "Envoyer"
|
||||
}
|
||||
|
||||
// Touche Échap → on vide la zone
|
||||
if (event.key === "Escape") {
|
||||
zoneMessage.value = "";
|
||||
rafraichirCompteur();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**✅ Teste :** écris un message, fais **Ctrl+Entrée** → l'envoi se déclenche. Appuie sur **Échap** → la zone se vide.
|
||||
|
||||
> 🔎 `event.key` te donne le **nom** de la touche (`"Enter"`, `"Escape"`, `"a"`…). `event.ctrlKey` est vrai si Ctrl est maintenue. C'est comme ça qu'on crée des raccourcis clavier.
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Ce que ce niveau ajoute à ta boîte à outils
|
||||
|
||||
- **DOM propre** : `createElement`, `textContent`, `append`
|
||||
- **Données distantes** : `fetch`, `async`/`await`, JSON, `try`/`catch`
|
||||
- **Temps réel** : `setInterval` / `clearInterval`
|
||||
- **Clavier** : `keydown`, `event.key`, raccourcis
|
||||
|
||||
Prochaine étape possible : organiser ton code en plusieurs fichiers/modules, ou afficher des données depuis une **vraie API publique** en ligne. Dis-moi vers quoi tu veux aller.
|
||||
|
||||
Note tes questions au fur et à mesure.
|
||||
Reference in New Issue
Block a user