Un avant goût
Dans la version précédente du cours j'avais tout expliqué dans le detail d'abord, puis montré comment se servir de javascript pour rendre une page interactive. Sans grand succès. Dans cette itération je vais d'abord vous fournir une vue d'ensemble en montrant comment construire ce petit projet. Puis dans le chapitre suivant on verra les détails de ce que nous avons utilisé dans ce chapitre.
Mise en place
Créez un nouveau projet, ouvrez le dans VSCode et collez le code ci-dessous dans un fichier index.html
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Incrementer example</title>
<style>
body {
min-height: 100vh;
margin: 0;
font-family: system-ui, sans-serif;
display: grid;
place-items: center;
font-size: 32px;
}
main {
display: flex;
align-items: center;
gap: 3rem;
}
button {
font-size: 1rem;
padding: 1rem;
}
</style>
</head>
<body>
<main>
<div id="count"></div>
<button>+</button>
</main>
<script>
// rappel: le javascript c'est ici
</script>
</body>
</html>
Cool, à partir de là on ne s'intéressera plus qu'au javascript.
Mettre la main sur un truc
En CSS il vous faut selectionner des éléments pour pouvoir leur appliquer des règles, eh bien on va se reservir de ces même sélecteurs. La fonction document.querySelector()
nous permet de sélectionner le premier élément qui correspond au selecteur CSS qu'on lui fournit.
Autrement dit, je peux dire à mon programme de sélectionner le boutton comme ceci
document.querySelector("button");
Si vous cherchez à executer ce bout de code, il n'y aura rien à voir. Mais je vous ai dit que console.log
était extrêmement utile, on peut s'en servir pour afficher autre chose que du texte. Essayons de s'afficher notre bouton.
console.log(document.querySelector("button"));
Avec cette ligne vous devriez voir votre bouton, que vous pouvez ouvrir et inspecter pour voir toutes les informations que le navigateur a desssus.
La vieille méthode
J'écris ça en 2024 et pourtant, pas mal de gens/tutos risquent encore de vous parler de document.getElementById()
. Je vous encourage a toujours utiliser document.querySelector()
parce que vous pouvez utiliser n'importe quel selecteur CSS plutôt que juste un id et pas autre chose.
Aussi, c'est beaucoup plus lisible d'un coup d'œil. Si je vois un #
entre les paranthèses de document.querySelector()
alors je sais que je fais de la sélection par identifiant, si je vois un .
entre ses paranthèses alors je fais de la sélection par classe, si ça ne commence par aucun charactère spécial alors c'est de la sélection par tag etc...
Cela dit, peut être que document.getElementById()
est plus rapide à faire pour la machine et aurais donc sa place, mais bon ... ce genre de considérations ne nous regarderont pas dans ce cours et ne regardent probablement pas non plus ceux qui vous le conseilleront.
Lire les infos d'un truc
On peut spécifier une propriété particulière avec un .
. Par exemple ...
document.querySelector("button").textContent;
J'attrape mon bouton avec document.querySelector("button")
puis dedans je récupère le texte qu'il contient, le tout en une seule ligne ce qui fait que le résultat du total est "le contenu textuel de mon bouton".
Et on peut verifier ça en se l'affichant :
console.log(document.querySelector("button").textContent);
Modifier un truc
Je peux aussi sélectionner une propriétes et lui donner une nouvelle valeur comme ceci
document.querySelector("button").textContent = "c'est mon bouton";
Ce coup-ci, pas besoin de console.log()
pour voir les effets de notre manip'.
Il faut savoir que =
ici veux dire que l'on rend la chose à gauche égale à celle de droite, donc cette ligne équivaux à "le textContent
du premier élément <button>
que l'on trouve dans le document devient égal à "c'est mon bouton"".
Exercice
En modifiant uniquement le javascript de votre projet, changez le texte de l'élément ayant l'identifiant count
. Donnez lui la valeur que vous voulez.
Rappel: Le sélécteur CSS pour les id est #
. Par exemple: #myId
. De la même manière que le sélécteur pour une classe est .
comme dans .myClass
.
Solution
document.querySelector("#count").textContent = 42;
ça marche aussi
document.querySelector("#count").textContent = "42";
Ce n'est pas très important tout de suite mais la différence est que dans le premier cas on lui donne le nombre 42 tandis que dans le deuxième cas on lui donne le texte "42".
Passer de l'action à l'intéraction
On peut demander à un élément particulier de réagir à certains types d'événements. Quand on lui demande ça il faut lui dire à quel type d'événement réagir et quoi faire.
Si je reprend mon bouton...
document.querySelector("button");
... il faut que j'aille chercher dans ce qu'il possède avec .
pour donner la commande "met toi à l'écoute d'un type d'événement".
document.querySelector("button").addEventListener(/*l'événement et quoi faire*/);
Si on écrit ceci ...
document.querySelector("button").addEventListener("click", handleClick);
... on demande à notre bouton d'éxécuter l'action handleClick
lorsequ'il est cliqué.
Remarquez que "click"
est encadré par des guillemets "
alors que handleClick
ne l'est pas. Ce qui est encadré dans des guillemets est purement du texte, le reste est du code, handleClick
est le nom d'une action/fonction qui n'existe pas encore, c'est à nous de la créer comme ceci.
document.querySelector("button").addEventListener("click", handleClick);
function handleClick() {
console.log("clique");
}
Ici "click"
est du texte parce que addEventListener()
est prévue comme ça, elle connais une liste d'événements, chaque événement correspondant à un texte, pour le moment on va se contenter de "click"
.
Et si on clique 7 fois sur notre bouton voici ce que l'on a dans la console.
On y est presque, on peut essayer de remettre ensemble tout ce qu'on viens de voir
document.querySelector("button").addEventListener("click", handleClick);
function handleClick() {
document.querySelector("#count").textContent = 1;
}
Bon, c'est marrant, mais on vois bien qu'il nous manque un truc parce qu'on reste coincé sur 1
, ce qui est normal vu que handleClick
assigne la valeur 1
au textContent
de l'élément #count
à chaque fois et c'est tout.
En sachant qu'on exécute le code contenu dans la fonction handleClick
à chaque fois que l'on clique sur le bouton. Ce serait bien si on pouvait garder en mémoire le nombre auquel on est rendu.
Et c'est ce qu'on va faire, on peut définir un nom auquel on peut associer une valeur comme ceci
let countNumber = 0;
let
est un mot-clef signifiant que l'on créer une "variable" qui est juste un nom associé à une valeur. Ici on créer le nom countNumber
et on lui associe la valeur 0
. Une fois que ce nom existe on peut lui donner une nouvelle valeur avec =
, comme ceci:
let countNumber = 0;
console.log("countNumber");
console.log(countNumber);
countNumber = 42;
console.log(countNumber);
Nous donnant ceci dans la console
Pour continuer d'illustrer la différence entre du texte brut et du code vous remarquerez que dans le premier console.log()
j'ai encadré countNumber
par des guillemets et c'est donc exactement ce que j'ai d'affiché. En revanche, quand je met countNumber
directement on parle bien la valeur countNumber
qui est d'abord 0
puis 42
.
La vieille méthode
Pareil, toujours en 2024, il y aura des gens pour vous montrer var
au lieux de let
. Ça pour le coup ce n'est pas justifiable.
let
à été introduit dans le langage en 2016 pour remplacer var
qui ouvrait la porte à trop de bugs et comportements foireux.
Et donc je peux tout remmetre ensemble comme ceci
document.querySelector("button").addEventListener("click", handleClick);
function handleClick() {
let count = 0;
count = count + 1;
document.querySelector("#count").textContent = count;
}
Essayez ce code ci-dessus.
Qu'est-ce que ça donne?
Ça donne la même chose parce qu'à chaque fois qu'on exécute le code contenu dans handleClick
on ...
- créer
count
qui vaux0
- puis on l'augmente de
1
en disant qu'il est maintenant égal à lui même + 1 - on dit que la valeur du texte de
#count
devient égale à la valeur decount
Mais il faut savoir qu'une variable, comme count
, n'existe que dans le "scope" (qu'on pourrait vaguement traduire par "environement") dans lequel elle a été créée, et sera détruite une fois que tout le code du scope aura été exécuté. Un scope est delimité par les accolades {}
qui nous encadrent le plus directement. Donc count
est créé dans le scope de handleClick
. Ce qui veux dire qu'à chaque fois qu'on fini d'exécuter le code de handleClick
on détruit count
que l'on recréera en partant du nombre 0
la prochaine fois que l'on exécutera handleClick
. Donc il faut sortir count
du scope de handleClick
pour qu'elle surive et garde sa mémoire entre deux exécutions de handleClick
.
let count = 0;
document.querySelector("button").addEventListener("click", handleClick);
function handleClick() {
count = count + 1;
document.querySelector("#count").textContent = count;
}
Et voila 🎉
Probleme : Faites un bouton -
qui fait redescendre le compteur de 1
quand on clique dessus.
Indice
Rappellez vous du tout début de ce chapitre, document.querySelector()
ne selectionne que le premier élément qui correspond. Maintenant nous avons 2 boutons, il faut donc un moyen de les différencier, pour ça on peut leur coller des identifiants.
Solution
html
<!-- [...] -->
<main>
<button id="minus-button">-</button>
<div id="count">0</div>
<button id="plus-button">+</button>
</main>
<!-- [...] -->
js
<script>
let count = 0;
document.querySelector("#minus-button").addEventListener("click", countDown);
document.querySelector("#plus-button").addEventListener("click", handleClick);
// ici je conserve `handleClick` pour changer le moins de choses possible
// mais je déteste ce nom parce qu'il explique mal ce qu'il fait
// `countUp` serait largement mieux.
function handleClick() {
count = count + 1;
document.querySelector("#count").textContent = count;
}
function countDown() {
count = count - 1;
document.querySelector("#count").textContent = count;
}
</script>