Aller au contenu
← 1001 Widgets
N° 001 · ●○○

Compteur JS

Compteur interactif avec boutons +/- et reset. Valeur colorée selon l'état.

HTMLCSSJS
Ce qu'on apprend
  • Garder une valeur dans une variable
  • Écouter un clic avec addEventListener
  • Mettre à jour le texte de la page
Pourquoi ce langage

Pourquoi HTML/CSS/JS vanilla et pas React ?

Parce que React, Vue, Svelte : tous ces frameworks font exactement ce que tu vas coder ici, mais en cachant la mécanique. Si tu ne comprends pas le vanilla JS, tu ne comprendras jamais vraiment ce que font les frameworks.

Ce compteur t'apprend le pattern fondamental de tout développement front-end moderne :

ÉTAT → ÉVÉNEMENT → MISE À JOUR DU DOM

C'est littéralement ce qu'est useState() en React. C'est ce qu'est data() en Vue. C'est ce qu'est writable() en Svelte.

Maîtrise ça en vanilla, et les frameworks deviennent évidents.

Comment ça marche
  1. L'ÉTAT

    Une seule variable représente la "vérité" du compteur. Règle absolue : on ne lit JAMAIS le DOM pour connaître la valeur actuelle. On lit toujours count. Pourquoi ? Le DOM peut mentir (formatage, innerHTML...). L'état en mémoire, lui, ne ment jamais.

    let count = 0
  2. LA FONCTION D'ACTION

    n peut être positif (+1, +10, +100) ou négatif (-1, -10, -100). Une seule fonction gère tout → moins de code, moins de bugs.

    function add(n) {
    count += n   // on modifie l'état
    update()     // on demande au DOM de se mettre à jour
    }
  3. LE RESET

    Remettre l'état à zéro, puis mettre à jour. Simple mais important : toujours passer par update(), jamais écrire directement dans le DOM depuis ici.

    function reset() {
    count = 0
    update()
    }
  4. LA MISE À JOUR DU DOM

    Cette fonction est le seul endroit où on touche au DOM. C'est le "Single Source of Truth" appliqué. Si demain tu changes le HTML, tu ne modifies qu'ici, pas dans add(), pas dans reset().

    function update() {
    const el = document.getElementById('count')
    
    // On écrit la valeur
    el.textContent = count
    
    // On change la classe CSS selon le signe
    // L'opérateur ternaire enchaîné : si positif → 'positive',
    // sinon si négatif → 'negative', sinon → 'zero'
    el.className = count > 0
    ? 'positive'    // vert
    : count < 0
    ? 'negative'    // rouge
    : 'zero'        // gris
    }
Pièges & optimisations

PIÈGE 1 : Lire le DOM comme état ❌ Mauvais : function add(n) { const current = parseInt(el.textContent) el.textContent = current + n } → Tu lis le DOM pour connaître la valeur. Si le texte contient autre chose qu'un chiffre (un espace, une unité...) : bug immédiat.

Fix

Correct : toujours lire count, jamais el.textContent.

PIÈGE 2 : Dupliquer la logique ❌ Mauvais : function increment() { count++; el.textContent = count } function decrement() { count--; el.textContent = count } function add10() { count += 10; el.textContent = count } → Si tu changes l'affichage, tu le changes 3 fois.

Fix

Correct : une seule fonction add(n) + une seule update().

Optimisation 1

Limites min/max function add(n) { // Empêche le compteur de dépasser -100 et +100 count = Math.max(-100, Math.min(100, count + n)) update() }

Optimisation 2

Persistance localStorage function update() { const el = document.getElementById('count') el.textContent = count el.className = count > 0 ? 'positive' : count < 0 ? 'negative' : 'zero' // Sauvegarde automatique à chaque changement localStorage.setItem('compteur', count) }

// Au chargement de la page, on restaure la valeur const saved = localStorage.getItem('compteur') if (saved !== null) { count = parseInt(saved) update() }

Optimisation 3

Animation au changement // Dans ton CSS : // .bump { animation: bump 200ms ease; } // @keyframes bump { 0%,100% { transform: scale(1) } // 50% { transform: scale(1.15) } }

function update() { const el = document.getElementById('count') el.textContent = count el.className = count > 0 ? 'positive' : count < 0 ? 'negative' : 'zero' // Rejoue l'animation à chaque changement el.classList.remove('bump') void el.offsetWidth // force le reflow : astuce pour reset l'animation el.classList.add('bump') }

Optimisation 4

Touches clavier // Pour les power users : flèches haut/bas du clavier document.addEventListener('keydown', (e) => { if (e.key === 'ArrowUp') add(1) if (e.key === 'ArrowDown') add(-1) if (e.key === 'r' || e.key === 'R') reset() })

→ React

ce que tu viens d'apprendre // Ton code vanilla : let count = 0 function add(n) { count += n; update() }

// Devient en React : const [count, setCount] = useState(0) const add = (n) => setCount(prev => prev + n)

// C'est exactement la même chose. // useState = ta variable count // setCount = ta fonction update() automatisée // React re-render = ton el.textContent = count // La logique est identique. Seule la syntaxe change.

Personnaliser

Édite les variables CSS et observe le résultat en temps réel.

Variantes
Commentaires
0/1000

Chargement des commentaires…