Tous les articles

jQuery : l’événement !

Par Pierre Bertet

Enfin « les », événements. Je voulais un titre sensationnel.

Vous connaissez certainement jQuery, l’excellente bibliothèque Javascript. Non ? Alors c’est ici.

Le développement DOM/Javascript repose en grande partie sur les événements. Vous savez certainement qu’il est possible d’affecter un événement à un objet jQuery, c’est à dire qu’une fonction se déclenchera lors d’un événement sur l’objet sélectionné.

jQuery propose deux manières de définir les événements : nous allons les analyser.

Les « Event Helpers »

Joli nom. Pas très causant, mais sympa comme tout.

Il s’agit d’une série de méthodes, reprenant le nom des événements DOM. Elles prennent comme unique paramètre une fonction, et leur nom correspond à celui de l’événement DOM, allégé de son préfixe « on » (onclick, onmouseout, etc. ).

Si aucun paramètre n’est passé, cette méthode déclenche l’événement.

Si une fonction est passée en paramètre, elle s’exécutera lorsque l’événement sera déclenché (depuis le code comme vu juste au-dessus, ou « naturellement »).

Vous trouverez la liste complète de ces méthodes sur la page de documentation des événements : http://docs.jquery.com/Events.

Définir un événement

Commençons par un exemple. Tout le monde aime les exemples !

L’événement onclick peut être défini sur un objet jQuery à l’aide de la méthode click() à laquelle est passée une fonction :

$("a#test1").click(function(){
  window.alert("Clic sur a#test1.");
});

La fonction passée en paramètre peut attendre un paramètre. Il représente l’objet événement, et possède plusieurs propriétés et méthodes. J’ai l’habitude d’utiliser une variable nommée « e » (event), mais on peut évidemment utiliser un autre nom.

La méthode preventDefault() de cet objet permet d’empêcher le navigateur de déclencher son comportement par défaut.
Sur un lien, cette méthode empêchera simplement le navigateur de le suivre.

Exemple.

$("a#test1").click(function(e){
  e.preventDefault(); // Empêche le navigateur de suivre le lien.
  window.alert("Clic sur a#test1.");
});

Démonstration : a#test1

Déclencher un événement depuis le code

Il est parfois utile de déclencher un événement depuis le code. Pour cela, les mêmes méthodes seront appelées, mais cette fois sans paramètre.

Un exemple. « 例 », dirait un japonais, mais vous n’êtes pas obligé de me croire.

Nous allons réutiliser l’événement précédemment défini dans le premier exemple, en le déclenchant depuis le code.

Lorsque le lien du second exemple ( « a#test2 » ) sera cliqué, un clic sera déclenché sur le lien du premier exemple ( « a#test1 » ).

Exemple.

$("a#test2").click(function(e){
  e.preventDefault();
  window.alert("Clic sur a#test2, déclenchement du clic sur a#test1...");
  $("a#test1").click();
});

Démonstration : a#test2

La méthode ready()

Vous avez certainement déjà utilisé la méthode ready() d’un objet jQuery contenant l’objet DOM document.

Si un script est défini et exécuté dans la partie <head> d’une page et qu’il essaie de manipuler des éléments, le navigateur se comportera comme s’ils n’existaient pas.

Le script est exécuté au moment où il est lu par le navigateur (sauf avec l’attribut defer). Puisque la suite du document n’a pas encore été chargée, le navigateur n’a pas connaissance de ces éléments.

Pour remédier à cela, il est possible d’attacher un événement onload sur l’objet window, qui sera déclenché lorsque la page et tous ses éléments seront chargés.

Exemple.

$(window).load(function(){
  // Le code placé ici sera déclenché
  // au chargement complet de la page.
});

Il s’agit de l’équivalent jQuery du célèbre window.onload = function(){}. Évidemment, si un élément appelé sur votre page met un certain temps à répondre (une image hébergée ailleurs, ou votre outil d’analyse de statistiques basé sur un script externe), un long moment peut s’écouler avant que votre script ne soit exécuté.

C’est pourquoi la méthode ready() de l’élément document a été créée : la fonction affectée à cet événement sera déclenchée dès que le document HTML et les CSS seront chargés.

Le mécanisme de cet événement jQuery est plutôt intéressant. Il ne s’agit pas d’un événement natif DOM, ou pas tout à fait : Mozilla Firefox, Opera et les dernières versions de Webkit déclenchent bien un événement DOMContentLoaded lorsque le document HTML est chargé, mais Opera n’attend pas que les styles soient chargés pour le déclencher. On ne peut pas vraiment lui donner tort, puisque sur le brouillon de la spécification HTML5 rien n’est précisé à propos du chargement des styles.

jQuery résout ce problème sur Opera en attendant que chaque feuille de style soit disponible. Pour cela, la propriété disabled de chacun des objets contenus dans document.styleSheets (chaque fichier CSS) est testée jusqu’à ce qu’elle renvoie false, c’est à dire lorsque la CSS est chargée.

Pour Internet Explorer, l’astuce consiste à tester la méthode document.documentElement.doScroll("left"); jusqu’à ce qu’elle ne retourne plus d’erreur. Dès que c’est le cas, cela signifie que les styles sont chargés.

Pour Webkit, c’est la propriété document.readyState qui est testée, puis un test similaire à celui utilisé pour Opera se charge de vérifier le chargement complet des CSS.

Certains navigateurs supportent l’événement document.DOMContentLoaded (Mozilla Firefox), c’est donc ce dernier qui est utilisé.

Pour les navigateurs ne supportant pas document.DOMContentLoaded et n’entrant pas dans les cas particuliers traités par jQuery (Opera, Webkit, Internet Explorer), c’est un simple événement window.onload qui est utilisé.

Voilà, vous oubliez ça, jQuery le fait pour vous :

function bindReady(){
	if ( readyBound ) return;
	readyBound = true;

	// Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
	if ( document.addEventListener && !jQuery.browser.opera)
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", jQuery.ready, false );

	// If IE is used and is not in a frame
	// Continually check to see if the document is ready
	if ( jQuery.browser.msie && window == top ) (function(){
		if (jQuery.isReady) return;
		try {
			// If IE is used, use the trick by Diego Perini
			// http://javascript.nwbox.com/IEContentLoaded/
			document.documentElement.doScroll("left");
		} catch( error ) {
			setTimeout( arguments.callee, 0 );
			return;
		}
		// and execute any waiting functions
		jQuery.ready();
	})();

	if ( jQuery.browser.opera )
		document.addEventListener( "DOMContentLoaded", function () {
			if (jQuery.isReady) return;
			for (var i = 0; i < document.styleSheets.length; i++)
				if (document.styleSheets[i].disabled) {
					setTimeout( arguments.callee, 0 );
					return;
				}
			// and execute any waiting functions
			jQuery.ready();
		}, false);

	if ( jQuery.browser.safari ) {
		var numStyles;
		(function(){
			if (jQuery.isReady) return;
			if ( document.readyState != "loaded" && document.readyState != "complete" ) {
				setTimeout( arguments.callee, 0 );
				return;
			}
			if ( numStyles === undefined )
				numStyles = jQuery("style, link[rel=stylesheet]").length;
			if ( document.styleSheets.length != numStyles ) {
				setTimeout( arguments.callee, 0 );
				return;
			}
			// and execute any waiting functions
			jQuery.ready();
		})();
	}

	// A fallback to window.onload, that will always work
	jQuery.event.add( window, "load", jQuery.ready );
}

Vous l’aurez compris, il s’agit d’un extrait du code de jQuery.

Il existe deux autres « Event Helpers » particuliers, appelés « Interaction Helpers ». Les deux fonctionnent de la même manière, à la différence qu’ils attendent deux fonctions en paramètre plutôt qu’une.

La méthode hover() permet de spécifier deux événements, pour l’entrée et la sortie du curseur souris dans la zone que couvre le ou les éléments de notre objet jQuery. Mon vieil ami Superman appelle ce comportement le « survol ».

Ils ne sont pas tout à fait équivalents aux événements onmouseover et onmouseout, existant nativement en DOM.
En utilisant ces derniers, lorsque le curseur se déplace d’un élément à un autre au sein de l’élément sur lequel est attaché l’événement (par exemple lorsqu’il passe sur une image se trouvant à l’intérieur d’un élément <div>), onmouseover sera déclenché sur l’image (sur laquelle aucun événement n’est défini), et « remontera » jusqu’à son conteneur, pour déclencher une seconde fois l’événement. La cible de l’événement va également changer, ce sera l’image et non le conteneur.
En sortant le curseur de l’image, même problème : c’est cette fois l’événement onmouseout qui sera déclenché sur le conteneur, mais avec l’image pour cible.

Pour en savoir plus, c’est ici : http://www.quirksmode.org/js/events_mouse.html

Si nous ne voulons pas de ce comportement, il faut vérifier que l’élément survolé au déclenchement de l’événement corresponde bien à l’élément sur lequel l’événement a été défini. C’est fastidieux. jQuery s’en charge automatiquement lorsque vous utilisez hover().

La seconde méthode est toggle(). Elle est équivalente à la méthode click(), mais la deuxième fonction passée sera déclenchée une fois sur deux à la place de la première, ce qui est très intéressant, par exemple pour faire apparaître et disparaître en alternance un élément à chaque clic sur un bouton. Vous pouvez également passer plus de deux fonctions, elles seront alors exécutées les unes à la suite des autres, à chaque clic.

Les méthodes bind et trigger (affecter et déclencher)

La méthode bind()

Vous pouvez utiliser la méthode bind() pour affecter un ou plusieurs événements à un objet jQuery. Voici une première différence avec les « Event Helpers » vus au-dessus. Le premier paramètre doit être une chaîne de caractère, représentant les événements (séparés par des espaces) sur lesquels sera exécutée la fonction passée en deuxième paramètre. Allez !

Exemple.

$("a#test3").bind("mouseover mouseout", function(e){
  $(this).text( "-- " + $(this).text() + " --" );
});

Démonstration : a#test3

Deux événements « spéciaux » sont disponibles avec la méthode bind() : mouseenter et mouseleave.
Ils correspondent à l’entrée la sortie du curseur sur un élément, sans déclencher l’événement lorsqu’un élément enfant est survolé. Ces événements correspondent à ceux définis par la méthode hover().

La méthode trigger()

Comme pour les « Event Helpers », il est possible de déclencher depuis le code un événement défini sur un élément. La méthode trigger() sera utilisée.

Exemple.

$("a#test4").bind("click", function(e){
  e.preventDefault();
  jQuery("a#test3").trigger("mouseover");
});

Démonstration : a#test4 : un clic sur ce lien déclenchera un survol sur l’élément a#test3 (démonstration précédente)

Supprimer un événement avec unbind()

Supprimer un événement est trivial. Il suffit d’appeler la méthode unbind() en lui passant en paramètre le ou les événements à supprimer. Si aucun événement n’est passé en paramètre, tous les événements affectés à cet objet jQuery seront supprimés.

Vous avez également la possibilité de passer en second paramètre une référence vers une fonction en particulier, de manière à ne pas supprimer toutes les fonctions attachées à cet événement.

Exemple.

function affiche1(){
  window.alert('1');
};
function affiche2(){
  window.alert('2');
};

$("#test").bind("click", affiche1);
$("#test").bind("click", affiche2);

// Si le script s'arrêtait ici, un clic sur l'élément afficherait "1" puis "2"

$("#test").unbind("click", affiche1);

// Mais la première fonction attachée à l'événement a été supprimée en passant sa référence, seul "2" est affiché

Passer des données à un événement

La méthode trigger() permet également d’envoyer des données à la fonction déclenchée par l’événement. On passera alors ces données en second paramètre, après le nom de l’événement. Elles seront regroupées dans un tableau, sauf si un seul paramètre est passé : vous avez alors la possibilité de le passer directement.

$("a#test5").trigger("click", ["paramètre 1", 2, {parametre: "3"}]);

Lors de la définition de l’événement avec la méthode bind(), la fonction passée en paramètre devra définir ces paramètres pour pouvoir les utiliser.
Tous les paramètres supplémentaires sont ajoutés après le premier, qui représente toujours l’objet événement (« e » dans l’exemple suivant).

Exemple.

$("a#test5").bind("click", function(e, param1, param2, param3){
  e.preventDefault();
  window.alert(param1); // Affiche "paramètre 1"
  window.alert(param2); // Affiche "2"
  window.alert(param3["parametre"]); // Affiche "3" (cet argument est un tableau associatif)
});

Démonstration (cliquez sur le bouton) : , a#test5

Essayez maintenant de cliquer sur le lien juste au-dessus, vous verrez que les paramètres ont la valeur undefined la boîte de dialogue déclenchée par window.alert ne s’affiche même pas pour le troisième paramètre : le fait d’appeler une clé inexistante (param3["parametre"]) déclenchera une erreur Javascript.

Comme dit plus haut, si un seul paramètre est passé, vous pouvez l’utiliser directement :

Exemple.

$("a#test5").trigger("click", "paramètre 1");

Bien entendu, la fonction n’attend qu’un paramètre dans ce cas :

$("a#test5").bind("click", function(e, param1){
  e.preventDefault();
  window.alert(param1); // Affiche "paramètre 1"
});

Les événements « sur mesure »

Il est possible d’utiliser bind() pour affecter un événement personnalisé. Cet événement ne pourra être déclenché qu’avec la méthode trigger().

– A quoi ça sert, exactement ?
– Principalement, à découper certaines parties d’un script, liées à un objet jQuery, en événements. Mais c’est quoi ces questions ? C’est pour me déstabiliser, c’est ça ?

Prenons un lien, auquel nous attacherons l’événement « StyleFunky ». Lorsque cet événement sera déclenché, notre lien va naturellement s’imposer dans le page, montrer à tous qu’il n’est pas le genre de lien qu’il fait bon prendre pour une ancre. En réalité, un ensemble de propriétés CSS seront définies sur cet élément, ainsi qu’un window.setInterval() pour changer sa couleur de fond, mais ce sera transparent pour nous, une fois notre fonction définie. Seul l’événement « StyleFunky » sera ensuite déclenché.

Nous attacherons également un autre événement à ce lien, « StyleNormal », qui annulera les effets de l’événement précédent (y compris le window.setInterval) :

Exemple.

$("a#test6").bind("StyleFunky", function(){
  var jElt = $(this);
  jElt
  .css({
    "display": "block",
    "padding": "20px",
    "fontSize": "300%",
    "fontWeight": "bold",
    "textAlign": "center",
    "color": "#fff",
    "background": "#f00"
  });
  jElt.data("redBackground", true);
  jElt.data("interval", window.setInterval(function(){
    if (jElt.data("redBackground")) {
      jElt.css("background", "#f0f")
    } else {
      jElt.css("background", "#f00");
    }
    jElt.data("redBackground", ! (jElt.data("redBackground")) );
  }, 500));
});
$("a#test6").bind("StyleNormal", function(e){
  var jElt = $(this);
  window.clearInterval(jElt.data("interval"));
  jElt.css({
    "display": "inline",
    "padding": "0",
    "fontSize": "100%",
    "fontWeight": "normal",
    "textAlign": "left",
    "color": "#7F89A6",
    "background": "none"
  });
});

Demostración (c’est de l’espagnol) :

a#test6

Les Namespaced Events (événements nommés)

Nous avons vu qu’il était possible avec unbind() de supprimer une seule des fonctions attachées à un événement, mais cette méthode est peu élégante, puisqu’elle n’autorise pas l’utilisation de fonctions anonymes.

Pour remédier à cela, jQuery permet de nommer une fonction attachée à un événement.
Une notation similaire à celle des classes CSS est utilisée, accolée au nom de l’événement (« .action1 », « .action2 » et « .action3 » ici) :

$(element).bind("click.action1", function(){ /* Action 1 */ });
$(element).bind("click.action2", function(){ /* Action 2 */ });
$(element).bind("click.action3", function(){ /* Action 3 */ });

Il sera alors possible de déclencher un événement en particulier en ciblant une fonction événement en particulier, ou toutes les fonctions attachées, en déclenchant simplement l’événement « click » :

$(element).trigger("click.nom1"); /* Déclenche l'action 1 */
$(element).trigger("click"); /* Déclenche les actions 1, 2 et 3 */

Évidemment, il sera possible de les supprimer, individuellement, ou non.

$(element).unbind("click.nom1"); /* Supprime l'action 1 */
$(element).trigger("click"); /* Déclenche les actions 2 et 3 (la 1 vient d'être supprimée, sois attentif) */

La méthode .triggerHandler()

Pour finir, la méthode triggerHandler() permet de déclencher les différentes fonctions attachées à un événement, sans déclencher l’action par défaut du navigateur.

Prenons l’événement focus sur un champ texte de formulaire. Si vous lui affectez une action particulière (comme afficher une bulle d’information), vous pourrez alors déclencher cette action sans déplacer le curseur de l’utilisateur dans le champ :

$(input[type=text]).bind("focus", function(){ /* Affichage de la bulle d'information */ });
$(input[type=text]).trigger("focus"); /* Déplacement du curseur dans le champ texte, affichage de la bulle d'information */
$(input[type=text]).triggerHandler("focus"); /* Affichage de la bulle d'information seulement */

Voilà, c’est fini.

12 commentaires

Flux RSS des commentaires de cet article

jQuery : l’événement !…

Vous trouverez dans ce tutoriel les différentes manières d’utiliser les événements avec jQuery….

Le 16 Sep. 2008 à 13h33 par Anonyme

Bonjour,
Juste pour vous déclarer mon enthousiasme.
Je bosse actuellement dur sur un plugin WordPress : Events-Calendar. C’est passionnant et il y a beaucoup à faire. Allez donc voir un peu de quoi il s’agit sur mon blog ;)

Enfin bon, il y a quelques semaine je ne connaissais ni bian Javascript et encore moins jQuery et j’ai pas mal galérer.

Et là je tombe sur votre site et vos charmants tutos. Bah je sens que vous allez être mes nouveaux Dieux !

J’ai mille et une question évidemment. Mais je vais tout d’abord lire vos tutos avant de voir si ce sont vraiment des questions à poser ;)
Cordialement
Heirem

Le 25 Sep. 2008 à 16h42 par Heirem

C’est un excellent article, en tout cas, ça m’a permis de beaucoup mieux comprendre JQUERY :)

Merci beaucoup :)

Le 24 Oct. 2008 à 16h03 par Sun Location

Excellent article comme toujours.
Un peu fébrile, faut dire qu’il se fait tard ou tôt, enfin il fait nuit, j’ai plusieurs fois cliqué sur le « StyleFunky », ben très très speed le style et il ne veut plus devenir « StyleNormal ». J’espère pas avoir tout cassé.

JLMag

Le 30 Nov. 2008 à 05h38 par jlmag

j’ai un probleme ! avec IE tout fonctionne mais pas avec FireFox
j’utilise JQuery, j’aimerais que au moment que la page LOAD que mes TEXTAREA ce CACHE automatiquement lorsque la page ce load. avec la commande suivante:
$(‘#example’).hide().hide(‘fast’);

me comprenez-vous bien ?

Le 25 Août. 2009 à 16h11 par Mathieu St-Germain

Les commentaires sont fermés sur cet article.