JS Evénements

Identification

Infoforall

11 - Gestion des événements avec javascript


Nous allons apprendre aujourd'hui à gérer finement les événements sur la page Web.

Pour ceux qui connaissent déjà un peu Javascript, cette activité met totalement de côté l'objet Event pour l'instant. Il y a déjà bien assez à faire.

Logiciels : Il faudra utiliser un éditeur de code. On propose ici d'utiliser Atom produit par Githhub, aujourd'hui possédé par Google, ou Notepad ++ (Notepadqq sur Linux). Sublim Text est également une alternative de qualité.

Evaluation ✎ : questions 06.

1 - Rappel : les événements

Il existe une multitude d'événements.

Liste des événements

Voici les événements liés à la souris

Nom JavascriptDescription
clickOn clique et on relâche sur la balise.
dblclickPareil mais en clic double.
mousedownOn clique gauche sans relâcher sur la balise.
mouseupOn relâche gauche sur la balise.
mouseoverOn survole la balise
mousemoveOn déplace la souris sur l'élément.
mouseoutOn fait sortir la souris de la balise.

Voici les événements liés au clavier

Nom JavascriptDescription
keydownOn appuie sans relâcher sur l'une des touches.
keyupOn relâche une touche.
keypressOn appuie et relâche une touche.

Voici les événements liés à la sélection et la mise en focus ou ciblage

Nom JavascriptDescription
focusOn vient de mettre le focus ou cibler l'élément, par exemple en cliquant sur l'élément.
blurOn annule ce ciblage, par exemple en cliquant ailleurs.
loadLa balise est correctement chargée.

Il y a deux façons de surveiller un événement :

  1. Depuis le HTML : on insère un attribut ontruc directement dans la balise HTML.
  2. 1
    <p>Couleur voulue : <input type="text" name="couleur" onchange="action();"></p>

    On notera bien qu'on fait précéder le nom de l'événement par on.

  3. Depuis Javascript : si on connaît l'identifiant de la balise, il suffit de faire ceci :
  4. 1
    <p>Couleur voulue : <input type="text" name="couleur" id="couleur" ></p>

    Dans Javascript :

    js1 js2
    var reference = document.getElementById('couleur'); reference.addEventListener("change", action);

    On remarque bien qu'ici l'événement "change" est créé en utilisant la méthode addEventListener sur la référence de la balise HTML.

  5. Si la balise peut gérer les attributs name, on peut les insérer dans des formulaires :
  6. html1 html2 html3
    <form name="formulaire"> <p>Couleur voulue : <input type="text" name="couleur" ></p> </form>
    js1 js2
    var reference = formulaire.couleur; reference.addEventListener("change", action);

Jusqu'à présent, nous avons surtout utilisé la méthode 1 : c'est simple, rapide et on a pas besoin de connaitre la référence de la balise.

Nous allons voir aujourd'hui les avantages de la méthode addEventListener.

2 - Exercice pratique

Assez de blabla.

On vous demande de réaliser une interface HTML comportant cinq images de votre choix. Dans la mesure où vous n'aurez qu'à fournir le code et pas à uploader les images, insérez les images en utilisant une URL externe plutôt qu'une adresse locale.

On veut que lorsqu'on double-clique sur l'une des images celle-ci disparaisse sans que l'espace occupé ne soit remplacé par une autre image!

Sauf l'avant-dernière image : sur un double-clic on veut que l'image disparaisse réellement et que la cinquième image prenne donc sa place.


✎ 01° Réaliser l'interface demandée en vous aidant de la documentation présente ci-dessous. Pour les images, vous pouvez prendre celles que vous voulez. Il va falloir lire et comprendre la documentation ci-dessous et utiliser les connaissances vues précédemment !

Quelques aides et indications :

Evénement double-clic

Nous avons les événements load et click.

Sachez qu'il existe aussi l'événément dblclick qui permet de générer des événements lorsqu'on double clic sur un élément.

En utilisant un attribut de balise dans HTML

1
<img id="image_1" ondblclick="image_cliquee()" src="https://doc.infoforall.fr/commun/images/accueil_HTML5_150.png">

En rajoutant manuellement un événement dans JAVASCRIPT

1
reference_balise.addEventListener("dblclick",image_cliquee);
CSS : rendre une balise visible ou cachée

Il existe une propriété CSS permettant d'afficher ou non une balise présente dans le code HTML

Il s'agit de la propriété visibility.

Pour rendre toutes les images visibles via le CSS

1
img { visibility:visible); }

Si vous voulez n'en cibler qu'une, il suffit d'utiliser un identifiant dans le HTML et utiliser #nom dans le CSS.

Si vous voulez en cibler plusieurs mais pas toutes, il suffit d'utiliser une classe dans le HTML et utiliser .nom dans le CSS.

Pour rendre une image visible via Javascript, si on connait sa référence

1
ref_balise.style.visibility = "visible";

Il s'agit bien entendu du réglage par défaut : pas la peine de le placer pour afficher les balises. Par contre, ça permet de rendre visible des balises que vous avez cachées précédemment.

Commment cacher une balise ?

En anglais, to hide veut dire cacher.

Pour cacher toutes les images visibles via le CSS

1
img { visibility:hidden); }

Si vous voulez n'en cibler qu'une, il suffit d'utiliser un identifiant dans le HTML et utiliser #nom dans le CSS.

Si vous voulez en cibler plusieurs mais pas toutes, il suffit d'utiliser une classe dans le HTML et utiliser .nom dans le CSS.

Pour rendre une image visible via Javascript, si on connait sa référence

1
ref_balise.style.visibility = "hidden";

Attention, avec hidden, la balise n'apparaît pas à l'écran mais elle garde la place qu'elle devait occuper à l'écran. On obtient donc un emplacement vide que les autres balises ne peuvent pas combler.

Visuel avec l'image visible Visuel avec l'image cachée
Comparaison des deux affchages obtenus avec visibility: visible ou visibility: hidden
CSS : faire réellement disparaitre une balise et son espace reservé de l'affichage

Il existe une propriété CSS permettant de faire réellement disparaitre la balise et de laisser l'espace libre pour d'autres balises.

Il s'agit de la propriété display.

Commment faire réellement faire disparaitre de l'affichage une balise ?

En anglais, to hide veut dire cacher.

Pour faire disparaitre toutes les images et l'espace reservé de l'affichage via le CSS

1
img { display:none); }

Si vous voulez n'en cibler qu'une, il suffit d'utiliser un identifiant dans le HTML et utiliser #nom dans le CSS.

Si vous voulez en cibler plusieurs mais pas toutes, il suffit d'utiliser une classe dans le HTML et utiliser .nom dans le CSS.

Pour rendre une image visible via Javascript, si on connait sa référence

1
ref_balise.style.display = "none";

Contrairement à visibility: hidden, la balise n'apparaît pas à l'écran et on ne garde pas la place réservée.

Visuel avec l'image visible Visuel avec dispariton d'image
Comparaison des deux affchages obtenus avec display: hidden

Et comment revenir au mode d'affichage par défaut par les images ?

Pour afficher en mode par défaut toutes les images via le CSS

1
img { display:inline-block); }

Pourquoi inline-block ? Simplement car une image n'est pas block (on ne passe pas à la ligne par défaut) mais on peut régler sa taille avec width et height (ce qui n'est pas le cas des balises inline).

Si vous voulez n'en cibler qu'une, il suffit d'utiliser un identifiant dans le HTML et utiliser #nom dans le CSS.

Si vous voulez en cibler plusieurs mais pas toutes, il suffit d'utiliser une classe dans le HTML et utiliser .nom dans le CSS.

En Javascript, avec la référence d'une balise

1
ref_balise.style.display = "inline-block";

3 - Désactiver une surveillance avec removeEventListener

Voyons maintenant l'un des points forts de l'utilisation de addEventListener pour gérer une surveillance d'événement : on peut faire l'inverse, c'est à dire arrêter de surveiller !

remoteEventListener

Cette méthode s'utilise exactement comme addEventListener et permet d'annuler la surveillance qui avait été déclenchée.

Si vous avez lancé une surveillance de cette façon :

1
document.getElementById('image_2').addEventListener("click",image_cliquee);

Vous pourrez stopper la surveillance avec ceci :

1
document.getElementById('image_2').removeEventListener("click",image_cliquee);

A titre d'exemple, voici un code qui transforme l'image lorsqu'on clique sur le premier texte CHANGEMENT.

CHANGEMENT

FINI A TOUT JAMAIS

Enfin, rien n'est vraiment jamais fini !

Par contre, si on clique sur le deuxième texte FINI A TOUT JAMAIS, on annule la gestion de l'événement précédent.

Et on génére une nouvelle surveillance : si on clique sur Enfin, rien n'est vraiment jamais fini !, on change encore l'affichage de l'image.

Profitons de ce moment pour parler d'un des plus graves problèmes d'Internet : la folie du chaton.

02° Lancer le code ci-dessous pour visualiser l'effet obtenu. Répondre ensuite aux questions suivantes :

  1. Pourquoi a-t-on une image initiale alors que la source de la ligne 13 est vide ?
  2. Sur quelle ligne se trouve l'annulation de l'événement 'Clic sur le paragraphe CHANGEMENT' ?

...CORRECTION...

Lors du chargement de la page, on lance la fonction demarrage.
Dans cette fonction, on lance sur la ligne 42 la fonction mise_a_jour.
Lors dans la fonction mise_a_jour, on va chercher le contenu de l'attribut scr. Comme il est vide initialement, on atteint la ligne 27 et on effectue la ligne 28 où on affecte l'une des URLs à la source src.

On le trouve à la ligne 34. Elle s'active donc lors de l'appel à la fonction stopper_mais_pas_vraiment qui est activée lors de l'événement 'Clic sur le paragraphe FINI A TOUT JAMAIS'. Cette activation a été faite sur la ligne 41 au démarrage de la page.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8" /> <title>Gestion des événements</title> </head> <body> <main> <h1>Remove remove</h1> <p id="change">CHANGEMENT</p> <p><img id="image" src=""><p> <p id="fin" style="text-align : center;">FINI A TOUT JAMAIS</p> <p id="encore" style="text-align: right;">Enfin, rien n'est vraiment jamais fini !</p> </main> <script> function changer_image() { /* Procédure qui se charge de modifier la source de l'image affichée */ var ref_image = document.getElementById('image'); var url1 = "https://doc.infoforall.fr/activite/javascript/images/evenements/chat_1.png"; var url2 = "https://doc.infoforall.fr/activite/javascript/images/evenements/chat_2.png"; if (ref_image.src == url1) { ref_image.src = url2; } else { ref_image.src = url1; } } function stopper_mais_pas_vraiment() { /* Procédure qui désactive la gestion sur le premier paragraphe mais en crée un autre*/ document.getElementById('change').removeEventListener("click", changer_image); document.getElementById('encore').addEventListener("click", changer_image); } function demarrage() { /* Procédure qui se lance automatique lorsque la page est chargée */ document.getElementById('change').addEventListener("click", changer_image); document.getElementById('fin').addEventListener("click", stopper_mais_pas_vraiment); changer_image(); } window.addEventListener('load', demarrage); </script> </body> </html>

4 - Rappel : Opérateur this dans un attribut

Nous avons déja vu que la façon la plus simple de trouver la référence de la balise ayant activéé un événement est d'utiliser l'opérateur this. Cet opérateur va renvoyer la référence de l'objet dans lequel this apparait. Si on le place dans l'attribut onclic d'une balise img, c'est bien la balise qui est le contexte d'exécution de this au moment où this sera évalué.

13 14
<img onclic="image_cliquee(this)" src="https://doc.infoforall.fr/commun/images/accueil_HTML5_150.png"> <img onload="image_cliquee(this)" src="https://doc.infoforall.fr/commun/images/accueil_js_150.png">

Le this visible ci-dessus contiendra bien la référence de la balise img et pas l'objet window
On utilise image_cliquee en lui donnant ce this en tant qu'argument.

Et qui va recevoir l'argument this ?
Le paramètre nommé reference_balise. Puisque la fonction était déjà créé autant garder son code !

19 20 21 22 23
function image_cliquee(reference_balise) { alert(reference_balise.src); reference_balise.width = 100; reference_balise.height = 200; }

Du coup, pas besoin de sortir getElementById et de rajouter un ID à chaque balise.

Voici le programme dans sa totalité 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8" /> <title>Gestion des événements</title> </head> <body> <main> <h1>Gestion au clic</h1> <img onclick="image_cliquee(this)" src="https://doc.infoforall.fr/commun/images/accueil_HTML5_150.png"> <img onclick="image_cliquee(this)" src="https://doc.infoforall.fr/commun/images/accueil_js_150.png"> </main> <script> function image_cliquee(reference_balise) { alert(reference_balise.src); reference_balise.width = 100; reference_balise.height = 200; } </script> </body> </html>

03° Utiliser ce nouveau code HTML et javascript intégré et répondre à la question suivante : pourquoi cette fois l'effet est-il le même sur les deux images ?

...CORRECTION...

Tout simplement car on applique le même code aux deux images cette fois ! Il n'y a plus qu'une seule fonction. On pourrait donc faire la même chose avec toutes les images.

Si vous n'utilisez que l'une des deux propriétés de dimensionnement, l'image sera transformée en proportion.

5 - Opérateur this et addEventListener

Voyons maintenant comment associer l'utilisation de l'opérateur this avec l'utilisation de la méthode addEventListener.

04° Regardez le code ci-dessous sans le lancer.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8" /> <title>Gestion des événements</title> </head> <body> <main> <h1>Gestion au clic</h1> <img id="image_1" src="https://doc.infoforall.fr/commun/images/accueil_HTML5_150.png"> <img id="image_2" src="https://doc.infoforall.fr/commun/images/accueil_js_150.png"> </main> <script> function image_cliquee() { alert(this.src); this.width = 100; this.height = 200; } document.getElementById('image_1').addEventListener("click",image_cliquee); document.getElementById('image_2').addEventListener("click",image_cliquee); </script> </body> </html>

A votre avis, que vous contenir this cette fois ? Pour répondre, il faut vous demander qui gère l'événement.

Pour rappel, il s'agissait de window lorsqu'on avait utilisé ceci :

1
window.addEventListener("click",demarrage);

...CORRECTION...

La réponse est : ça dépend.

Pourquoi ?

Tout simplement car la fonction où apparait le this est utilisée par un événement géré par

25 26
document.getElementById('image_1').addEventListener("click",image_cliquee); document.getElementById('image_2').addEventListener("click",image_cliquee);

Lorsque l'événement est provoqué par un clic sur la première image, c'est donc la référence de la première balise img qui est stockée dans this.

Lorsque l'événement est provoqué par un clic sur la deuxième image, c'est donc la référence de la deuxième balise img qui est stockée dans this.

05° Lancer le code pour vérifier vos réponses précédentes.

Choix de la méthode à utiliser : préférez addEventListener

Comme toujours en informatique, les deux choix sont possibles mais l'une et l'autre auront des avantages en fonction des moments.


Ancienne méthode : attribut de balise dans HTML

Si vous n'avez pas besoin de connaitre la référence de la balise pour l'action à effectuer, autant utiliser l'attribut directement dans la balise HTML.

1
<img id="image_1" onclick="image_cliquee(this)" src="https://doc.infoforall.fr/commun/images/accueil_HTML5_150.png">

C'est plus simple mais attention néamoins : il s'agit d'une version plutôt ancienne d'agir. Les normes actuelles favorisent plutôt la méthode du addEventListener.


Nouvelle méthode : utilisation du gestionnaire d'événement de JAVASCRIPT

Si vous avez besoin de la référence de la balise qui provoque l'événement, autant utiliser la méthode avec addEventListener. L'utilisation de this est plus simple. Et cette version permet en plus d'utiliser plein d'options que nous ne détaillerons pas ici.

1
document.getElementById('image_2').addEventListener("click",image_cliquee);

Moralité : préférez le deuxième méthode mais sachez que la méthode de l'attribut existe.

6 - Travail final

Vous allez devoir modifier l'exécution d'une interface qui ressemble à cela :

Je vous propose une structure de base un peu plus bas. Attention, on place tout dans le HTML : le style et le script. Ne faites pas cela pendant les projets réels. Il s'agit ici uniquement de gagner un peu de temps.

J'ai également fait le choix de ne pas utiliser de formulaires, pour vous montrer qu'avec un peu de CSS, on pourrait recréer des formulaires. M'enfin, c'est un peu bête puisque l'outil existe déjà. Mais comme cela, vous pourrez voir qu'un formulaire n'est qu'un code préexistant.

N'oubliez pas : les déclarations des fonctions ne sont pas ce qu'il faut regarder en premier. L'exécution du code javascript commence en réalité à la ligne 77 !

✎ 06° Complétez le code du projet ci-dessous pour qu'il ressemble au projet proposé dans la vidéo.

Il vous faudra d'abord vous approprier le code en l'analysant et en suivant son déroulé, pas à pas.

Cela vous permettra de voir ce que le code exécute ou non pour l'instant.

Une fois cela fait, il vous restera à compléter la fonction mise_a_jour.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8" /> <title>Exercice final</title> </head> <body> <style> span { background-color: black; color: white; width: 50px; display: inline-block; text-align: center; } </style> <main> <h1>Une page de calcul en ligne&nbsp;?</h1> <p>Que vaut le calcul suivant ?</p> <p><span id="premier_nombre">5</span> x <span id="deuxieme_nombre">5</span> = <span id="reponse">-</span></p> <p id="texte"></p> <p id="nouveau">CLIQUEZ ICI POUR UN NOUVEAU CALCUL</p> </main> <script> function renvoyerEntier(max) { /* Fonction qui renvient un entier dans l'intervalle [0;max] :: param max(number) :: un nombre entier :: precondition : max est bien un entier positif :: return (number) :: un entier compris entre 1 et max inclu */ return Math.floor(Math.random()*Math.floor(max)) + 1; } function verifier() { /* Fonction qui vérifie le calcul et renvoie true ou false */ var a = parseInt( document.getElementById("premier_nombre").innerHTML ); var b = parseInt( document.getElementById("deuxieme_nombre").innerHTML ); var ref_reponse = document.getElementById("reponse"); var reponse = ref_reponse.innerHTML; if (reponse == '') { ref_reponse.innerHTML = '-'; } else { reponse = parseInt(reponse) } var bonne_reponse = a * b; return reponse == bonne_reponse; } function mise_a_jour() { /* Procédure à compléter : elle doit mettre à jour les couleurs et le texte en fonction de la réponse de la fonction verifier */ } function en_blanc() { document.getElementById("reponse").style.color = 'white'; } function nouveaux_nombres() { /* Fonction-procédure qui modifie les deux nombres et impose une couleur blanche dans la réponse*/ document.getElementById("premier_nombre").innerHTML = renvoyerEntier(10); document.getElementById("deuxieme_nombre").innerHTML = renvoyerEntier(10); document.getElementById("reponse").style.color = 'white'; } function demarrage() { document.getElementById('nouveau').addEventListener("click", nouveaux_nombres); var ref_reponse = document.getElementById('reponse'); ref_reponse.addEventListener("blur", mise_a_jour); ref_reponse.addEventListener("focus", en_blanc); ref_reponse.contentEditable = 'true'; nouveaux_nombres(); } window.addEventListener("load",demarrage); </script> </body> </html>

7 - FAQ

Rien pour l'instant

Activité publiée le 11 01 2020
Dernière modification : 10 07 2020
Auteur : ows. h.