La gestion de l'interaction en javascript se fait selon un modèle de gestion des évènements qui a évolué au cours du temps et qui comporte aujourd'hui des styles de programmation un peu différents.
Un modèle de gestion des évènements inclut :
- la typologie des évènements reconnus.
- le modèle de diffusion des évènements (aussi appelé event dispatch ou event flow)
- la définition des callbacks (aussi appelées eventListener ou fonctions de rappel) et les mécanismes d'association callback-évènement-composant.
1. Typologie des évènements
La typologie de référence des évènements de base a été spécifiée en plusieurs versions dont les principales sont:
- DOM-Level-2 (2000) http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow
- DOM-Level 3 (2016) ui events http://www.w3.org/TR/DOM-Level-3-Events/)
Cette typologie comporte actuellement:
User Interface Event Types load event unload event abort event error event select event resize event scroll event |
Focus Event Types blur event DOMFocusIn event DOMFocusOut event focus event focusin event focusout event |
Mouse Event Types click event dblclick event mousedown event mouseenter event mouseleave event mousemove event mouseover event mouseout event mouseup event |
Wheel Event Types wheel event Keyboard Event Types keydown event keypress event keyup event |
Drag-and-Drop Events dragstart, drag, dragend - élément déplacé dragenter, dragleave, dragover - élément cible |
A ces typologies de base s’ajoutent les spécifications/implémentations des évènements tactiles permettant de gérer des surfaces tactiles multi-points. Dans ce domaine, deux versions principales :
Touch Events (2013) https://www.w3.org/TR/touch-events/
Touch Events 2 (2017) https://w3c.github.io/touch-events/
L’ensemble des principaux attributs et méthodes communs à tout évènement est rappelé dans le tableau ci-dessous
Attributs
event.bubbles
|
true/false
|
event.currentTarget
|
élément du chemin de propagation auquel l'évènement se trouve à gérer |
event.defaultPrevented
|
true/false
|
event.eventPhase
|
renvoie un entier identifiant : 1. → capture ,
2 → at Target , 3 → bubbling
|
event.target
|
target de l'évènement ie
élément le plus profond des éléments du chemin de propagation
de l'évènement
|
event.timeStamp
|
|
event.type
|
|
event.which
|
Renvoie la valeur Unicode de la touche dans un évènement clavier, qu'elle soit ou non un caractère. |
2. Flux d'évènements
Le flux d'évènements (aussi appelé event dispatch ou event flow) détermine comment les évènements "circulent" parmis les composants du DOM. Par exemple, lorsqu'un clic souris est émis, plusieurs élements peuvent être susceptibles de le gérer. La question se pose alors de savoir quels éléments du DOM pourront le traiter et dans quel ordre ces éléments pourront le traiter. Le modèle de flux permet de le déterminer.
Le modèle de flux de javascript comporte trois phases: (1) la phase de "capture" qui consiste à diffuser l'évènement de la racine du DOM vers la cible, (2) la sélection de la cible (élément le plus "bas" dans le DOM susceptible de traiter l'évènement) et (3) la phase de propagation ("bubbling" en anglais) qui remonte l'évènement de la cible vers la racine.
Par défaut, les évènements sont traités dans la phase de bubbling. Autrement dit, par défaut, lorsqu'un évènement est reçu par plusieurs composants imbriqués, les callbacks associées à ces composants sont appelées dans l'ordre des éléments de la cible vers la racine. Il est possible de changer cet ordre en utilisant la fonction addEventListener avec les bons paramètres pour faire l'attachement de la callback aux évènements/éléments (cf ci-dessous)
3. Callbacks
Les callbacks (fonctions de rappel, ou gestionnaires d'évènement) sont souvent utilisées pour gérer les évènements. Une callback est une fonction dont l'appel n'est pas direct.
Par exemple, on peut commencer par définir une fonction draw()
qui effectue le dessin d'un ensemble d'objets dans une fenêtre comme un canvas par exemple. Cette fonction draw
peut ensuite être passée en paramètre à la fonction addEventListener
pour être utilisée comme callback, c'est à dire, pour être appelée quand certains évènements se produisent et nécessitent un rappel à la fonction draw() pour rafraichir le dessin.
En javascript, il existe au moins trois manières d'associer une callback avec un type d'évènement et un élément du DOM:
- mode html - écriture dans l'attribut HTML de l'élément -
- exemple:
<div id="bouton" onclick="redraw()">
- DOM 0 affectation aux méthodes de l'élément
- exemple:
getElementById("bouton").click = redraw;
- DOM 2 argument de méthodes génériques de gestion d'évènement
- exemple:
getElementById("bouton").addEventListener("click",redraw, false);
- exemple:
Cette dernière, addEventListener(typeEvent, callbackName, useCapture)
, permet d'utiliser plusieurs callbacks pour un même élément et useCapture
permet d'expliciter la phase durant laquelle l'évènement est traité.
Si true
alors la callback est appelée dans la phase de capture, sinon elle est appelé dans la phase de propagation (bubbling).
Enfin, la callback peut facilement être retirée dynamiquement en utilisant la fonction removeEventListener(type, listener, useCapture)
. Attention cependant au fait que l'argument listener doit être identique à celui utilisé lors de l'ajout ce qui n'est pas le cas d'une callback anonyme.
Cependant, cette méthode étant relativement nouvelle, la question de la compatibilité de tous les navigateurs notamment avec l'argument useCapture
reste à vérifier.
4. Arguments, variables et portée
Selon les navigateurs, les variables auxquelles les callbacks ont accès peuvent différer. Selon le mode d'attachement de la callback à l'élément, aussi.
- mode html: dans certains navigateurs, la callback voit sa chaîne de portée augmentée automatiquement avec
document
,this
et même le formulaire englobant si la callback est associée à un élément de formulaire. Dans ces conditions, la callback a un accès direct à tous les attributs de l'élémént recevant l'évènement. Si l'élément est un champs de formulaire, la callback a un accès direct à tous les autres éléments du formulaire.NB: Quelques limites: (1) rien n'assure que les éléments de la chaîne de portée soient bien déjà chargés lorsqu'ils sont utilisés, (2) tous les navigateurs ne gèrent pas l'augmentation de chaîne de portée de la même manière, et (3) attention aux confusions/conflits de noms qui peuvent résulter de cette augmentation.
- DOM 0: la callback est considérée comme une méthode de l'élément qui reçoit l'évènement. Elle s'éxécute donc dans la portée de l'élément. Le recours à
this
dans la méthode est possible et référence alors l'élément qui a reçu l'évènement.