version 1.5.1, dernière mise à jour le 9 novembre 2016.
Dans le cadre d'une stricte séparation entre le fond, la forme et les comportements dynamiques d'une page, le fond est pris en charge par le code HTML
, la forme par la feuille de style CSS
et les comportements dynamiques par le JavaScript
.
L'utilisateur interagit avec une page par l'entremise d'événements.
La plupart des événements sont reliés à l'interface utilisateur du navigateur, tels les déplacements de souris, les actions sur des boutons ou des touches du clavier, les réponses à des formulaires... Ces événements sont en général reliés à un élément particulier dans la page. D'autres sont des événements activés en réponse à une action spécifique du navigateur (par exemple le chargement d'un document, voire d'une image seule).
Quelques objets ont des actions définies par défaut en réponse à certains événements. Par exemple, un clic sur un élément a
active le lien hypertexte, et force le navigateur à charger l'URL indiquée dans l'attribut href
.
En fait, tous les événements suivent le même modèle. Le DOM fournit des méthodes pour capturer les événements et lancer une action quelconque en réponse. Il définit également un objet event
, dont les propriétés permettent d'accéder à des informations spécifiques à l'événement (par exemple, quelle touche du clavier a été activée...).
Revenons un instant sur ce que recouvre la notion de Modèle Objet de Document. Cela signifie que tout nœud du document (à l'exception de l'élément racine bien entendu) possède une collection d'ancêtres dans l'arborescence. Par conséquent, quand par exemple on clique sur un élément, cela signifie que l'on clique aussi sur chacun des éléments qui le contiennent. Considérons par exemple le code HTML
ci-dessous :
<div>
<p>Un peu de texte dans un paragraphe.</p>
<p>Un autre texte dans un deuxième paragraphe.</p>
<p>Encore du texte dans un paragraphe, avec <a href="index.html">un lien</a>.</p>
</div>
Si on clique sur le lien dans le troisième paragraphe, sera généré un événement click. Mais on aura également cliqué sur le paragraphe contenant le lien, ainsi que sur l'élément div
contenant le paragraphe, aussi bien que sur l'élément body
englobant le tout...
N'importe lequel des éléments de cette chaîne peut avoir un gestionnaire d'événement associé au clic de souris, quel que soit l'élément duquel l'événement est parti.
Selon les standards, il existe deux manières pour un événement de « naviguer » de haut en bas de la chaîne d'éléments : il s'agit de l'event bubbling et de l'event capture.
Le comportement par défaut des éléments est appelée l'event bubbling. Il recouvre ce concept de remontée des événements le long de l'arborescence du fichier HTML
, tout comme une bulle monte dans un liquide. Un gestionnaire d'événement invoqué au cours de cette remontée de l'événement dans l'arborescence du DOM peut stopper cette remontée ; mais si rien n'est fait, l'événement poursuit sa propagation jusqu'à la racine. Tout élément rencontré dans l'arborescence au cours de cette phase peut avoir un gestionnaire d'événement.
Cette phase est appelée bubble phase dans le DOM. Tous les événements ne remontent pas de la sorte ; par exemple focus
et blur
ne remontent jamais. De même, certains événements ne peuvent être annulés à un moment quelconque de leur remontée. On peut le savoir grâce à l'objet event
et à ses propriétés, ainsi que nous le verrons.
Le pendant de la phase de bubbling est la phase de capture. En effet, par exemple dans le cas d'un clic, le logiciel commence par détecter qu'un clic a eu lieu. Il lui faut ensuite explorer l'arbre pour identifier l'élément sur lequel l'utilisateur a cliqué. Il est possible de lancer un gestionnaire d'événement quand le navigateur inspecte l'arbre en descendant dans l'arborescence. Ainsi, la phase de capture a lieu en premier ; l'événement descend le long de l'arborescence du document depuis la racine jusqu'à l'élément, avant de remonter.
Lors de cette phase, un élément parent est affecté par un événement avant que ce dernier ne se propage jusqu'à l'élément sur lequel l'événement a effectivement eu lieu. Cela permet de gérer des priorités, et permet d'intercepter un événement pour un élément, quel que soit l'élément descendant de ce dernier sur lequel l'événement a effectivement eu lieu. Dans notre exemple précédent, le clic sur le lien aurait d'abord été géré par le gestionnaire d'événement de l'élément body
, puis celui du div
, puis celui du paragraphe, enfin celui du lien.
L'exemple suivant montre la remontée et descente des événements dans la structure du DOM
Des événements sont liés à beaucoup d'éléments HTML
. On peut accéder à ces événements par un simple appel à un attribut décrivant la nature de l'événement (c'est ce que nous avons fait tout au long des cours précédents). Le nom de cet attribut se construit en préfixant par on
le nom de l'événement. L'exemple suivant montre comment utiliser un attribut pour définir un événement.
<span style="background-color: yellow" onmouseover="this.style.backgroundColor='black" onmouseout="this.style.backgroundColor='yellow">
Un élément avec un gestionnaire de base.</span>
En fait, tout se passe comme si, lors de l'appel au code JavaScript
dans chaque attribut, le navigateur créait dynamiquement une fonction anonyme contenant le code inscrit dans l'attribut. L'exemple suivant montre comment lancer une boîte d'alerte affichant le contenu de l'attribut onclick
de l'élément sur lequel on a cliqué.
<span style="background-color:yellow;" onclick="alert(this.onclick)">
Exemple de contenu avec un événement <code>click</code>.</span>
Le code précis de la fonction dépend du navigateur utilisé, mais le principe reste le même. Cette fonction est appelée le gestionnaire d'événement.
Attention, certains événements ne sont pas applicables à n'importe quel élément. Par exemple, les événements focus
et blur
(qui désignent respectivement l'action de sélectionner un élément par la souris ou l'emploi de la touche Tabulation, et l'action de le désélectionner) ne sont applicables qu'aux champs de formulaire et aux liens.
Netscape
et Mozilla
créent une fonction portant le nom de l'événement et utilisant un unique argument, event
, qui est l'objet événement passé comme paramètre au gestionnaire d'événements.
function
onclick(event){
alert(this.onclick) ;
}
Internet Explorer
utilise une fonction anonymous
. Il ne suit pas le standard, et donc aucun argument n'est défini (nous y reviendrons plus loin).
function
anonymous(){
alert(this.onclick) ;
}
Opera
utilise une fonction anonymous
avec un argument event
.
function
anonymous(event){
alert(this.onclick) ;
}
N'importe quel attribut n'est pas utilisable avec n'importe quel élément.
onclick
(clic simple), ondblclick
(double clic), onmouseover
(la souris entre au-dessus de la boîte de l'élément), onmouseout
(la souris quitte la boîte de l'élément), onmouseleave
(la souris quitte la boîte de l'élément et de tous ses enfants), onmousedown
(un bouton de la souris est enfoncé), onmouseup
(un bouton de la souris est relaché), onmousemove
(la souris se déplace au-dessus de la boîte de l'élément), onkeypress
(une touche est enfoncée puis relachée), onkeydown
(une touche est enfoncée) et onkeyup
(une touche est relachée) sont disponibles pour la très grande majorité des éléments courants.
onload
et onunload
sont utilisables avec les éléments body
et frameset
, et sont activés dans le premier cas dès que le corps du document a été chargé (ou que la page est fermée), ou dans le second, quand tous les cadres enfants du frameset
ont été chargés (ou fermés).
onsubmit
et onreset
s'appliquent uniquement à un élément form
, et sont activés à la soumission ou à la remise à zéro d'un formulaire.
onselect
est utilisable pour les éléments input
et textarea
. Il est activé quand l'utilisateur sélectionne une zone de texte dans le champ.
onchange
est utilisable pour les éléments input
, select
et textarea
, et est normalement activé quand l'utilisateur modifie un de ces champs de saisie.
Enfin, onfocus
et onblur
sont utilisables avec les éléments a
, area
(zone d'image dans une image cliquable), label
(étiquette attachée à un élément de formulaire), input
, select
, textarea
et button
. Ils sont activés respectivement quand l'utilisateur sélectionne l'élément correspondant soit par la souris, soit par la tabulation.
Un inconvénient majeur de cette méthode est de mêler le code HTML
avec le code Javascript
. Cela complique la maintenance de l'un comme de l'autre.
Afin de pouvoir séparer un peu plus le traitement d'un événement du code HTML
auquel il s'applique, il est possible d'accéder aux événements en ne modifiant que le code Javascript
. Si un objet-élément a été précédemment identifié (par une méthode getElementById
, par exemple), alors l'événement visé est accessible comme une simple propriété de l'objet élément. L'exemple suivant montre comment utiliser une propriété de l'objet-élément pour définir un événement.
<span id="exemple1">Exemple avec un événement souris.</span>
et le code JavaScript
associé :
document.getElementById('exemple1').onmouseover = miseEnGras ;
document.getElementById('exemple1').onmouseout = normal ;
function
miseEnGras(event){
this.style.fontWeight="bold" ;
this.style.color="red" ;
}
function
normal(event){
this.style.fontWeight="normal" ;
this.style.color="" ;
}
Il est à remarquer qu'on affecte à la propriété onmouseover
la valeur miseEnGras
, autrement dit, le nom de la fonction sans les parenthèses. Si on avait écrit miseEnGras()
, au moment de l'affectation de l'événement à l'objet-élément, la fonction aurait été évaluée. En affectant le nom de la fonction, en fait on affecte un objet de type function
à l'événement, ce qui reproduit le mécanisme interne d'affectation d'un gestionnaire à un événement vu plus haut.
Utiliser une propriété pour affecter un événement à un élément n'est pas la manière la plus « orientée objet » de coder. Il est ainsi difficile pour le code JavaScript
de se manipuler lui-même afin de modifier le gestionnaire attaché à un élément particulier.
Un moyen plus respectueux d'une conception orientée objet est d'ajouter des « event listeners » aux éléments. Cela offre en outre l'avantage de permettre le rattachement d'un gestionnaire à plusieurs événements (chose qui, certes, n'était pas interdite par la méthode précédente), mais aussi de facilement affecter plusieurs gestionnaires en réponse à un même événement, sur un élément donné, en fonction du contexte et/ou de ce qui s'est passé. Cela permet aussi de spécifier un comportement différent lors du « cascadage » des événements d'un élément à son parent -ou à un de ses enfants. Nous y reviendrons. Enfin, il est possible d'affecter des événements à n'importe quel nœud de l'arborescence, y compris un nœud de type texte. Pour mémoire, comme un nœud de ce type ne comporte pas d'attribut, il ne possède pas par exemple de propriété onmouseover
.
La syntaxe de base est la suivante :
noeud.addEventListener(eventType, fonction, useCapture) ;
noeud.removeEventListener(eventType, fonction, useCapture) ;
où eventType
est un événement prédéfini, comme mouseover
ou click
(il reprend le même nom que celui de l'attribut correspondant, mais sans le "on"), fonction
est le nom de la fonction gérant l'événement, et useCapture
un booléen qui spécifie dans quelle phase du flot d'événement la fonction sera appelée.
Par exemple, pour continuer avec le même cas que précédemment, on aurait pu écrire
var
el=.document.
getElementById("exemple1") ;
el.addEventListener("mouseover", miseEnGras, false) ;
el.addEventListener("mouseout", normal, false) ;
Des gestionnaires supplémentaires auraient pu tout aussi bien être affectés à cet élément :
el.addEventListener("mouseover", autreGestionnaire, true) ;
el.addEventListener("mouseover", etUnTroisieme, false) ;
De même, on peut les supprimer...
el.removeEventListener("mouseover", autreGestionnaire, true) ;
el.removeEventListener("mouseout", etUnTroisieme, false) ;
Il faut spécifier le même useCapture
que lors de l'ajout du gestionnaire. En effet...
el.addEventListener("mouseover", miseEnGras, true) ;
el.addEventListener("mouseover", miseEnGras, false) ;
... crée deux event listeners uniques, appelant certes la même fonction, mais actifs lors de phases différentes.
Internet Explorer
jusqu'à la version 8 incluse, et Opera
jusqu'à la version 5 incluse ne supportent pas les event listeners. Internet Explorer 9
les supporte cependant. Internet Explorer
fournit les méthodes attachEvent
et detachEvent
qui permettent d'affecter ou de détacher plusieurs gestionnaires pour un même événement. Par exemple :
var
el = .document.
getElementById("sample1") ;
el.attachEvent("onmouseover", highlight) ;
el.attachEvent("onmouseover", highlight2) ;
el.attachEvent("onmouseover", highlight3) ;
el.attachEvent("onmouseout", normal) ;
...
el.detachEvent("onmouseover", highlight2) ;
el.detachEvent("onmouseover", highlight3) ;
Plusieurs remarques s'imposent :
Ces méthodes ne permettent pas de spécifier la phase de l'événement (voir plus loin) ;
Elles ne peuvent pas être utilisées avec des nœuds de type texte ;
Elles ne font pas partie des standards, et ne sont donc supportées que par Internet Explorer
.
Plusieurs développeurs ont mis au point des librairies de méthodes JavaScript
, compatibles avec un maximum de navigateurs. Elles complètent des manques (par exemple elles ajoutent souvent une méthode getElementsByClassName
), ou bien pallient des bogues. Elles permettent de manipuler les événements de manière totalement transparente, sans faire appel à de multiples tests pour tenir compte de plusieurs navigateurs.
Nous avons déjà signalé qu'à tout appel de gestionnaire d'événement, un objet de type événement est passé en argument à la fonction. Plusieurs propriétés décrivent cet objet et son état. On peut les utiliser, notamment, afin de déterminer d'où est issu l'événement, et à quelle étape précise de son « voyage » il en est (montée ou descente...). Il est également possible de l'intercepter, et de faire en sorte qu'il cesse sa propagation.
Nom de la propriété |
Description |
---|---|
|
Un booléen indiquant si l'événement remonte l'arborescence ou non. |
|
Un booléen indiquant si l'événement peut être annulé. |
|
Le nœud auquel est affecté le gestionnaire d'événement. |
|
Un entier indiquant l'étape où l'événement se trouve dans le flot : il vaut soit |
|
Le nœud d'où est parti l'événement. |
|
L'heure à laquelle l'événement a eu lieu. |
|
Une chaîne de caractères donnant le type d'événement, comme |
Nom de la méthode |
Description |
|
Peut être utilisé pour annuler l'événement. Cela empêche le navigateur de procéder à l'action par défaut pour l'événement, comme par exemple charger une URL quand un lien a été cliqué. Attention, l'événement va continuer sa propagation le long de l'arbre. |
|
Coupe le flot de l'événement. Cette méthode peut être utilisée lors de la phase de remontée ou de descente. |
Table 1. Propriétés et méthodes de l'objet event
.
Les versions d'Internet Explorer
inférieures ou égales à 8 ne supportent pas le modèle event
du W3C. Au lieu de passer un argument de type event
à la fonction, ces versions recourent à un objet global, window.event
, qui contient le même genre d'informations.
Malheureusement, les propriétés et méthodes de cet objet ne suivent pas les mêmes conventions de notation que celles du W3C.
Standard W3C |
|
Remarques |
---|---|---|
|
aucun |
Voir ci-dessous. |
|
aucun |
Ne s'applique pas à |
|
|
Le nœud d'où est issu l'événement. |
|
aucun |
Non applicable à |
|
|
Même fonction que dans le standard. |
|
|
Propriété à mettre à |
|
|
Propriété à mettre à |
Table 2. Équivalents Internet Explorer ≤8
pour les propriétés et méthodes de l'objet Event
.
Afin d'obtenir un équivalent de la propriété currentTarget
avec Internet Explorer ≤8
, il faut utiliser le mot-clef this
comme argument lors de l'appel au gestionnaire :
<cite onmouseover="monGestionnaire(event, this)">
<a href="http://www.paroles.net/texte/18608/artis/1005">Mon légionnaire</a>
</cite>
function
monGestionnaire(event, toto){
alert("Il sentait bon le sable chaud")
}
Cette possibilité n'existe toutefois pas lorsque l'on utilise la méthode propriétaire attachEvent
pour allouer un gestionnaire d'événement.
Les événements souris sont :
click
dblclick
mousedown
mouseup
mouseover
mouseout
mouseleave
mousemove
select
qui est activé lors de la sélection de texte
contextmenu
, qui est activé quand un clic droit est détecté, ou quand la touche de menu contextuel est enfoncée ; cet événement est activé avant le lancement du menu contextuel.
wheel
est activé quand la molette de la souris est tournée.
Nom de la propriété |
Description |
---|---|
|
Booléens. Ils valent |
|
Un entier indiquant quel bouton de souris était enfoncé : 0=gauche, 1=milieu, 2=droit. Une souris à un seul bouton (type Mac) ne retournera que la valeur 1 ; une souris à deux boutons retournera les valeurs 0 ou 2. |
|
Donne les coordonnées du pointeur de la souris quand l'événement a eu lieu, par rapport à la fenêtre du navigateur effectivement disponible (hors barre de défilement). |
|
Sur un |
|
Donne les coordonnées du pointeur de la souris quand l'événement a eu lieu, par rapport à l'écran. |
Table 3. Liste des propriétés de l'objet event
liées à la souris.
Les événements souris sont toujours attachés à l'élément de plus bas niveau dans l'arborescence. Par exemple, cela sera le lien si l'utilisateur a cliqué sur un lien inclus dans un paragraphe.
Lors du clic, trois événements ont lieu, toujours dans le même ordre : mousedown
, mouseup
et click
. Ces événements sont toujours traités successivement, le traitement de chacun d'eux ne pouvant débuter que si celui du précédent est terminé.
Opera
considère -de manière erronée- que les propriétés clientX et
et clientY
sont relatives à l'origine de la page (autrement dit, la largeur des barres de défilement est incluse).
Les conventions d'Internet Explorer
diffèrent encore des standards. Voici une liste des équivalences :
button
porte le même nom, mais ne retourne pas la même valeur. Dans le cas d'Internet Explorer
, le codage de l'entier est différent : 0=aucun bouton, 1=gauche, 2=droit, 3=gauche et droit, 4=milieu, 5=gauche et milieu, 6=milieu et droit, 7=gauche, droit et milieu.
relatedTarget
pour les versions précédant Internet Explorer 9 est remplacé par les deux propriétés fromElement
et toElement
, indiquant respectivement les éléments que la souris vient de quitter, et au-dessus duquel elle vient d'entrer.
Internet Explorer
met à disposition en revanche offsetX
et offsetY
, qui donnent les coordonnées du pointeur par rapport à l'élément ciblé.
Le DOM niveau 2 n'inclut pas de consigne à propos des événements clavier. Cependant, la recommandation HTML
permet l'utilisation de plusieurs attributs, et par conséquent des événements correspondants. Ce sont les événements keydown
, keypress
et keyup
, indiquant respectivement qu'une touche a été enfoncée, appuyée ou relevée. Dans le cas de la frappe d'une touche clavier, ces trois événements sont produits et gérés dans cet ordre. Netscape
(et par souci de rétro-compatibilité, FireFox
) et Internet Explorer
ont inclus des propriétés afin de permettre la gestion des événements clavier, et notamment le codage des touches du clavier éventuellement enfoncées. Heureusement, de fortes similitudes existent.
Dans FireFox
et Netscape
, le code ASCII de la touche enfoncée est donné par la propriété keyCode
quand l'événement keydown
a été activé, et par la propriété charCode
pour l'événement keypress
.
Internet Explorer
stocke le code Unicode de la touche dans la propriété keyCode
pour chacun des trois types d'événements.
Dans les deux cas, les événements keydown
et keypress
sont activés dès qu'une touche quelconque est enfoncée (y compris une touche de fonction, ou une touche Ctrl, Shift ou Alt). Pour saisir une combinaison de touches comme Shift-a, par exemple, il est nécessaire d'avoir recours à l'événement keypress
.
Voici quelques exemples de codes renvoyés par ces propriétés pour Internet Explorer
et FireFox
. Il ne faut pas oublier que certaines combinaisons de touches sont interceptées par le système d'exploitation (par exemple souvent Ctrl-n pour ouvrir une nouvelle fenêtre). De plus, certaines extensions sous Firefox redéfinissent leurs propres raccourcis clavier. Selon le système et le navigateur, vous aurez accès à ces combinaisons de touches ou non.
Touche(s) |
|
|
|
---|---|---|---|
a |
|
|
|
shift |
|
|
Inapplicable. |
shift-a |
L'événement est actif, quelle que soit la touche enfoncée. |
L'événement est actif, quelle que soit la touche enfoncée. |
|
z |
|
|
|
ctrl |
|
|
Inapplicable. |
ctrl-z |
L'événement est actif, quelle que soit la touche enfoncée. |
L'événement est actif, quelle que soit la touche enfoncée. |
|
Table 4. Exemples d'événements clavier pour Internet Explorer
.
Touche(s) |
|
|
|
---|---|---|---|
a |
|
|
|
shift |
|
|
Inapplicable. |
shift-a |
L'événement est actif, quelle que soit la touche enfoncée. |
Chaque touche renvoie un événement séparé ; de plus, |
|
z |
|
|
|
ctrl |
|
|
Inapplicable. |
ctrl-z |
L'événement est actif, quelle que soit la touche enfoncée. |
Chaque touche renvoie un événement séparé ; de plus, |
|
Table 5. Exemples d'événements clavier pour Netscape
et Mozilla
.
On consultera la liste détaillée des nombreux événements sur le site du Mozilla Developer Network. Voici une petite sélection d'événements particulièrement intéressants...
resize
est activé quand la fenêtre est redimensionnée, scroll
quand on fait défiler le document, ou bien un élément.
Ces événements sont nécessaires à l'utilisation de l'attribut draggable
de HTML5
. Il s'agit de drag
et drop
au début et à la fin de la phase de drag&drop, dragstart
, dragend
quand le drag&drop est terminé, dragenter
qui est activé quand on entre au-dessus d'une zone où l'objet en cours de déplacement peut être déposé, dragleave
quand on sort d'une zone où l'objet peut être déposé, et dragover
au survol.
Il s'agit, très classiquement, de copy
, cut
et paste
.
animationstart
et animationend
sont activés récemment au début et à la fin d'une animation, tandis qu'animationiteration
est activé à chaque boucle.
Ces événements sont particulièrement utiles quand on doit gérer des Progressive Web Applications : online
et offline
sont des événements qui sont activés quand le navigateur obtient, ou perd, une connexion au réseau.
Cette création est mise à disposition par Gilles Chagnon sous un contrat Creative Commons.