« Tutoriel JavaScript côté client » : différence entre les versions

De EduTech Wiki
Aller à la navigation Aller à la recherche
mAucun résumé des modifications
Ligne 14 : Ligne 14 :


* [[Tutoriel JavaScript de base]]
* [[Tutoriel JavaScript de base]]


===Rappel de la structure d'une page web===
===Rappel de la structure d'une page web===

Version du 12 mai 2016 à 17:42

JavaScript
◀▬▬▶
à améliorer intermédiaire
2016/05/12
Prérequis
Voir aussi

Introduction

Ce tutoriel présente un survol des caractéristiques principales du langage JavaScript relatives à l’utilisation « côté client », c’est-à-dire l’utilisation la plus fréquente dans des pages/applications web à l’intérieur d’un navigateur. JavaScript permet en effet de "dynamiser" le contenu d'une page une fois qu'elle est disponible dans le navigateur. Pour suivre les exemples disponibles dans ce tutoriel il faut une connaissance de base du langage. Voir :

Rappel de la structure d'une page web

Avant d'aborder JavaScript, il est utile de rappeler la structure d'une page web qui se compose généralement de trois éléments :

  • HTML : cet élément détermine le contenu de la page, c'est-à-dire les éléments textuels et graphiques affichés à l'écran.
  • CSS : cet élément détermine la mise en page, la manière de présenter les éléments HTML de la page. On peut déterminer à travers les CSS les couleurs, les polices, l'alignement des éléments, etc.
  • JavaScript : cet élément ajoute des interactions et des comportements (ou effets) au contenu et/ou à la présentation de la page. Ces phénomènes permettent de modifier la page sans la nécessité d'actualiser le navigateur.

Outils pour le développement et le débug

Pour développer en JavaScript seulement deux outils sont strictement nécessaires :

  • Un navigateur web
  • Un éditeur de texte

Des outils supplémentaires peuvent sans doute rendre le développement plus aisé. Voici une liste de ces outils :

JavaScript et le navigateur web

L'avantage de JavaScript côté client consiste dans le fait que les navigateurs web disposent d'un "moteur" qui permet d'évaluer le code JavaScript et l'exécuter à chaque fois qu'une page web, contenant du code JavaScript, est téléchargée par l'utilisateur. Ceci est possible surtout grâce à deux phénomènes :

  1. L'inclusion de code JavaScript dans des pages HTML ;
  2. L'existance d'un objet global window qui permet à JavaScript d'interagir avec le navigateur web.

Utilisation du code JavaScript dans une page HTML

Il existe trois manières différentes d'utiliser du code JavaScript dans une page web :

  1. Fichier externe : le code est écrit dans un fichier avec extension .js
  2. Code "inline" : le code est écrit directement dans la page web elle-même
  3. Attribut des balises (déconseillé) : le code est écrit dans des attributs des balises des éléments HTML de la page. Cette option, utilisée souvent dans le passé, est aujourd'hui fortement déconseillée et ne sera par conséquent pas illustrée dans ce tutoriel.

Les trois différents manières peuvent être utilisées en même temps, il n'est pas nécessaire de choisir une seule manière pour toute la page.

Fichier externe

Dans le cas d'utilisation d'un fichier externe, ce fichier doit être créé avec l'extension .js. Dans ce fichier doit être contenu seulement du code JavaScript. Le code peut commencer dès la première ligne, il ne faut pas déclarer le type de fichier par exemple à travers une balise XML.

Pour rendre disponible le code d'un fichier externe dans une page web, il faut inclure le lien au fichier dans la balise HTML script et plus précisément à travers l'attribut src. Voici un exemple :

<script src="path/to/file.js"></script>

Veuillez noter que la balise script doit être fermée avec la balise de clôture même si à l'intérieur d'une balise avec attribut src il ne faut pas insérer de code.

Le lien au fichier .js suit les règles des liens hypertextuels à tout autre type de fichier, y compris les liens à d'autres pages HTML. On peut donc avoir un lien :

  • Absolu : le lien présente tout le URL du fichier, e.g. <script src="http://tecfa.unige.ch/path/to/file.js"></script> (ce fichier n'existe pas)
  • Relatif à la racine du domaine, e.g. <script src="/path/to/file.js"></script>. Veuillez noter le / initial qui détermine la racine du domaine. Dans ce cas la page HTML et le fichier JS doivent se trouver sur le même domaine (e.g. http://tecfa.unige.ch)
  • Relatif à la position du fichier HTML, e.g. <script src="../path/to/js"></source>.

Les positionnement relatifs utilisent une notation qui combine un . ou deux .. points et un slash / :

  • <script src="./file.js"></script> : le fichier file.js se trouve dans la même position (i.e. même dossier sur le serveur) de la page HTML
  • <script src="file.js"></script> : le fichier file.js se trouve dans la même position de la page HTML (équivalent à l'exemple précédent et utilisé plus souvent)
  • <script src="assets/js/file.js"></script> : le fichier file.js se trouve dans un dossier "js" qui se trouve à l'intérieur du dossier "assets". Le dossier "assets" se trouve à l'intérieur du dossier qui contient également la page HTML.
  • <script src="../file.js"></script> : le fichier file.js se trouve directement dans le dossier "parent" du dossier qui contient la page HTML
  • <script src="../js/file.js"></script> : le fichier file.js se trouve à l'intérieur du dossier "js" qui se trouve dans le dossier "parent"
  • <script src="../../../../file.js"> : le fichier file.js se trouve 4 niveaux "plus haut" par rapport à la page HTML

Le mauvais pointage d'un fichier externe est une des raisons les plus communes d'erreur dans le code JavaScript et il est par conséquent la première chose à contrôler en cas de problèmes. Une manière simple pour tester les liens à des fichiers JavaScript externes consiste à utiliser le code source de la page HTML. Certains navigateurs permettent en effet de cliquer sur le lien et ouvrir directement le fichier JS. La vidéo suivante montre cette opération en Google Chrome : si le lien est mauvais, le fichier ne sera pas trouvé.

Utiliser le code source de la page HTML pour tester les liens à des fichiers JS externes (en Google Chrome).

On utilise des fichiers externes souvent dans ces conditions :

  • Le même fichier contient du code qui est utilisé dans plusieurs pages d'un site, ce qui évite la nécessité de l'écrire dans toutes les pages. De cette manière, une modification au code doit se faire à un seul endroit et sera automatiquement activé dans toutes les pages.
  • Le fichier est une bibliothèque JavaScript
  • Il y a beaucoup de code écrit

Code inline

Une autre manière très utilisée d'inclure du code JavaScript consiste à écrire le code directement à l'intérieur de la balise script. Dans ce cas, il ne faut pas déclarer l'attribut src. Voici un exemple :

<script>
alert("Bonjour!");
</script>

La balise script peut contenir seulement du code JavaScript. Dans des exemples sur le web vous pouvez parfois trouver des balises script qui présentent aussi l'attribut type="text/javascript". Cet attribut n'est plus nécessaire car tout navigateur considère automatiquement le code inséré dans cette balise comme du code JavaScript.

On utilise du code "inline" souvent dans ces conditions :

  • Le code doit être exécuté précisément à cet endroit dans la page, par exemple parce qu'il ajoute du texte ou des éléments HTML.
  • Le code est spécifique à une seule page du site est le code n'a pas de probabilité d'être utilisé ailleurs
  • Le code est court
  • Le code sert à configurer des options ou initialiser une bibliothèque JavaScript

Placement de la balise script

Un élément auquel il faut faire attention est le placement de la balise script dans la page HTML. Il faut en effet tenir compte de la manière progressive de charger une page des navigateurs web. Avec le code JavaScript on fait souvent référence à des éléments du DOM (i.e. des balises HTML contenu dans la page). Il faut faire attention dans ces cas à ce que cet élément soit déjà disponible au navigateur. Un exemple illustre cette problématique....

Nous allons récupérer le texte d'un paragraphe avec id="mon-texte" avec la fonction document.getElementById("mon-texte").innerHTML ; et ensuite nous utiliserons la fonction document.write() pour écrire ce contenu. En d'autres termes, le comportement attendu de la page est d'obtenir deux fois exactement le même texte. Les deux exemples du code suivant sont exactement les mêmes, mais dans un cas, la balise script est positionnée avant le paragraphe, et dans l'autre cas après.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>
<script>
var texte = document.getElementById("mon-texte").innerHTML;
document.write(texte);
</script>
<p id="mon-texte">Bonjour!</p>

</body>
</html>

Si le code est avant le paragraphe, le script n'a pas accès à l'élément du DOM qui correspond au paragraphe. Donc aucun texte ne sera écrit par la fonction write().

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>
<p id="mon-texte">Bonjour!</p>
<script>
var texte = document.getElementById("mon-texte").innerHTML;
document.write(texte);
</script>
</body>
</html>

Au contraire, si le code est placé après le paragraphe, son contenu sera réécrit par le script et apparaîtra donc à l'écran.

Même s'il existe des fonctions pour déclencher le code seulement une fois que toute la structure du DOM a été chargée dans le navigateur (e.g. window.onload), il est une bonne pratique d'inclure les balises script juste avant la balise de clôture /body :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>

<script>
//Mon code est mieux ici!
</script>
</body>
</html>

L'objet global window

JavaScript dépend de l'environnement dans lequel il est exécuté à la fois pour afficher les résultats des expressions (i.e. le output), mais également pour recevoir des inputs. Dans JavaScript côté client, cet environnement est représenté par le navigateur web et la communication I/O entre JavaScript et le navigateur web se fait à travers l'objet global window. Plus concrètement cela signifie que :

  1. JavaScript peut "intercepter" tous les événements qui concerne la fenêtre du navigateur comme par exemple les clicks, les changements d'URL, le scolling de la page, etc.
  2. JavaScript peut modifier certaines propriétés de la fenêtre, y compris son contenu.

Les deux opérations sont possible justement grâce à l'objet global window qui, en tant qu'objet, possède des propriétés et des méthodes. Comprendre l'objet global window peut contribuer à bien comprendre le langage, car en réalité tout le code source écrit en JavaScript côté client peut se diviser en deux catégories :

  1. Le code qui exploite les propriétés et méthodes mises à disposition par l'objet window
  2. Le code qui ajoute des propriétés (e.g. des variables) ou des méthodes (e.g. des fonctions) à l'objet global window

En effet, lorsqu'on déclare une variable, ce que nous sommes en train de faire c'est tout simplement d'ajouter une propriété avec le nom de la variable à l'objet global window. En d'autres termes, les deux lignes de code suivantes sont équivalentes :

var cours = "STIC I";
window.cours = "STIC I";

Le même principe s'applique aux fonctions :

function addTwo(x) {
  return x + 2;
}
addTwo(4); // -> 6
window.addTwo(7); --> 9

En raison du fait que tout appartient à l'objet window, on peut éviter de le déclarer à chaque fois. Le même principe s'applique aux propriétés et méthodes déjà disponibles. Par example la fonction alert() - qui affiche une boîte popup avec un message - est en réalité la méthode window.alert().

De suite une liste non exhaustive des propriétés et méthodes déjà disponible avec l'objet window, pour une liste exhaustive voir la référence de l'objet Window sur W3Schools.

Les boîtes popup de JavaScript

Pour le débutant, créer quelques simples boîtes popup permet se lancer dans la programmation. On peut par exemple poser une question à un utilisateur et ensuite la traiter, puis afficher le résultat.

JavaScript possède 3 sortes de boîtes popup :

  1. Les boîtes d'alerte
  2. Les boîtes de confirmation
  3. Les fenêtres de saisies.

Vous pouvez structurer votre message dans vos boites en insérant '\n' à la fin de vos phrases. Cela permettra de revenir à la ligne.

alert ('Première ligne.\n Deuxième ligne.')
Alert.jpg

Les boites d'alerte

Elles affichent un message. Elles servent généralement à donner un message à un utilisateur ou à indiquer un message d'erreur. La boîte d'alerte contient un bouton 'Ok'.

Il faut utiliser la fonction alert(), c'est-à-dire l'équivalent de window.alert()

<html>
    <head>
        <script type="text/javascript">
            function gagné()
            {
                alert("Bravo vous avez trouvé");
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="gagné()" value="Trouver">
    </body>
</html>
Confirm.jpg

Les boîtes de confirmation

La fonction confirm() affiche une boite de confirmation. L'utilisateur a alors le choix entre 'OK' et 'annuler'.

<html>
    <head>
        <script type="text/javascript">
            function confirmer()
            {
                var reponse=confirm("Continuer l'operation en cours ?");
                if (reponse==true)
                {
                    alert("Vous avez cliqué sur OK");
                }
                else
                {
                    alert("Vous avez cliqué sur Annuler");
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="confirmer()" value="Choix" />
    </body>
</html>

Les fenêtres de saisie

Il est possible de créer une fenêtre pour saisir une valeur grâce à la fonction prompt(). La fonction prend deux paramètres : le premier est l'invitation à saisir du texte et le second propose un texte par défaut.

Après avoir entré une valeur, l'utilisateur peut cliquer sur 'ok' ou sur 'annuler.

Exemple : ici quand l'utilisateur clic sur 'Ok' la valeur saisie est indiqué dans la fenêtre d'alerte ensuite.

<html>
    <head>
        <script type="text/javascript">
            function saisir()
            {
                var reponse=prompt("Identification, veuillez saisir votre prenom","mon prenom");
                //si la réponse est non nul ou vide - donc l'utilisateur a appuyé sur ok
                if (reponse!=null && reponse!="")
                {
                    alert("Votre prenom est :"+reponse);
                } 
                 //autre cas : si l'utilisateur clic sur 'Annuler'
                else {
                    alert("Operation interrompue")
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="saisir()" value="Saisir mon prenom" />
    </body>
</html>
Prompt.jpeg


Prompt2.jpeg

Les fonctions liées au temps

Grâce à l'objet global window il est possibile d'exécuter du code en fonction du temps, plus spécifiquement :

  • setTimeout() permet d'exécuter du code une seule fois après une période de temps définie ;
  • setInterval() permet d'exécuter du code à des intervalles reguliers de temps.

setTimeout()

La syntaxe pour utiliser la fonction setTimeout() est la suivante :

setTimeout(function,milliseconds, [param1,param2,...]);

Les paramètres sont optionnels, tandis que la fonction à exécuter et le temps en milliseconds sont obligatoires. Voici un example qui affiche une boite d'alerte après 5 seconds (i.e. 5 * 1000 milliseconds) :

var afficherApres5seconds = setTimeout(function () { alert("Message"); }, 5000);

Il est également possibile de définir d'abord une fonction et ensuite passer son nom comme référence dans la fonction setTimeout() :

function alertMessage() {
  alert("Message");
}
var afficherApres5seconds = setTimeout(alertMessage, 5000);

Associer la fonction setTimeout() à une variable est utile si on veut annuler l'exécution de la fonction avant que la période de temps définie avec la notation :

clearTimeout(variable);

En ajoutant cette ligne de code à l'exemple précédent, la fonction alertMessage() ne sera pas déclenchée :

function alertMessage() {
  alert("Message");
}
var afficherApres5seconds = setTimeout(alertMessage, 5000);
clearTimeout(afficherApres5seconds);

setInterval()

La fonction setInterval est similaire à setTimeout() si ce n'est pour le fait que le code sera exécutée chaque X milliseconds. La syntaxe reste par contre la même :

setInterval(function,milliseconds, [param1,param2,...]);

Voici un exemple qui affiche dans la console un message chaque 3 seconds (sans arrêt si la page ne sera pas fermée ou après changement de URL) :

var chaque3seconds = setInterval(function () { console.log("...encore 3 seconds"); }, 3000);

Pour limiter les cycles on peut utiliser un conteur et utiliser la fonction clearInterval direcement à l'intérieur de la fonction invoquée par setInterval() :

var count = 0;
var cinqFois = setInterval(function () {
 count++; 
 console.log(count);
 if(count == 5) {
   clearInterval(cinqFois);
 }
}, 2000);

JavaScript et le DOM

Une des fonctionnalités les plus utilisées de JavaScript est sa capacité d'interagir dynamiquement avec le DOM, c'est-à-dire la structure hiérarchique des balises HTML d'une page web. C'est notamment grâce à la manipulation des éléments du DOM qui s'avèrent les interactions sur une page : apparition d'un message, déplacement d'un élément d'un endroit à un autre, changement de la taille d'une police, du couleur, etc.

Ces manipulations sont possibles grâce à l'objet document qui fait partie de l'objet global window (voir plus haut dans la page). Les propriétés, méthodes ainsi que les événements associés à cet objet permettent de manipuler le DOM.

NB: La manipulation du DOM à travers JavaScript "de base" est un bon point de départ pour comprendre la logique, mais pour des applications plus poussées les développeurs utilisent souvent des bibliothèques qui simplifient la syntaxe ou facilitent certains opérations. La bibliothèque la plus utilisée dans ce sens est jQuery.

Manipulation des éléments du DOM

Trouver un élément

Trois méthodes permettent d'identifier un élément dans la structure du document :

  • document.getElementById(id élément) : identifie un élément avec l'attribut id="..."
  • document.getElementsByTagName(nom de la balise) : identifie un ou plusiuers éléments avec le nom de la balise
  • document.getElementsByClassName(une ou plusieurs classes) : identifie un ou plusieurs éléments avec l'attribut class="..."

Une méthode plus générale est également disponible à travers les méthodes :

  • document.querySelector(css selector)  : cette méthode accepte des identifiants plus complexes par rapports aux trois méthodes vues plus haut dans la page, mais elle est également plus flexible, car elle permet d'identifier les éléments grâce aux selecteurs CSS. Cette méthode identifie le premier élément qui respecte les critères du selecteur.
  • document.querySelectorAll(css selector) : même principe, mais le résultat est un array avec tous les éléments qui respectent le critère de sélection.

Voici quelques exemples d'utilisation :

document.querySelectorAll("a.external") //cette méthode identifie toutes les balises a avec classe "external"
document.querySelectorAll("h1,h2,h3") //cette méthode identifie toutes les titres de h1 à h3

Cette fonction peut également être utilisée à l'intérieur des éléments du DOM :

var monParagraphe = document.getElementById("monTexte");
monTexte.querySelector("span").innerHTML = "Nouveau texte du span";

Ce code identifie le premier élément span à l'intérieur du paragraphe avec id="monTexte" et change le contenu textuel.

Modifier un élément

On peut modifier différentes caractéristiques d'un élément une fois identifié dans le document par exemple à travers ces propriétés :

  • element.innerHTML : modifie le contenu de la balise de l'élément sélectionné
  • element.attribute : modifie un attribut de la balise de l'élément sélectionné
  • element.style.property : modifie les propriétés de style de la balise de l'élément sélectionné

Ajouter ou supprimer un élément

On peut ajouter des éléments qui n'existent pas dans la structure de base du document ou supprimer des éléments existants. Exemples :

  • document.createElement() : définit un nouvel élément HTML
  • document.appendChild() : ajoute un élément à la structure existante
  • document.replaceChild() : remplace un élément existant par un autre élément
  • document.removeChild() : supprime un élément présent dans la structure

Exemples de manipulation

Dans la page suivante, 4 types de manipulation ont lieu lorsque la page a été chargée. L'expression window.onload = function () { ....} associe directement une fonction anonyme (sans nom) qui sera exécutée lorsque la page charge:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - exemple de manipulation du DOM</title>
</head>
<body>
 
<h1>JavaScript - exemple de manipulation du DOM</h1>

<p id="p1">Premier paragraphe.</p>
<p id="p2">Deuxième paragraphe.</p>
<p id="p3">Troisième paragraphe</p>
<p>Quatrième paragraphe.</p>
<div>Je ne suis pas un paragraphe!</div>

<script>

window.onload = function() {
  //1. On remplace le texte du premier paragraphe
  var p1 = document.getElementById("p1");
  p1.innerHTML = "Le texte du premier paragraphe a été modifié par JavaScript";
 
  //2. On ajoute une image au deuxième paragraphe
  var p2 = document.getElementById("p2");
  var image = document.createElement("img");
  image.src = "http://lorempixel.com/200/200/abstract";
  p2.appendChild(image);
 
  //3. On supprime le troisième paragraphe
  var p3 = document.getElementById("p3");
  document.getElementsByTagName("body")[0].removeChild(p3);
 
  //4. On change la couleur du texte des paragraphes
  var pp = document.getElementsByTagName("p");
  for(var i = 0; i < pp.length; i++) {
    document.getElementsByTagName("p")[i].style.color = "#F00";
  }
}
</script>
</body>
</html>

Les manipulations 1. et 2. ne nécessitent pas d'explication supplémentaire, tandis que la 3. et la 4. sont un peu plus complexes. Il faut considérer en effet que la méthode getElementsByTagName() renvoie un array d'éléments, c'est-à-dire un groupe d'éléments avec un indice (voir plus haut dans la page pour les Array). On identifie un élément d'un Array avec la notation nomDuArray[indice].

Dans la manipulation 3. nous avons identifié d'abord la balise body car il s'agit de la balise "parent" du paragraphe 3 qu'on veut supprimer. Bien qu'il n'y ait généralement qu'une seule balise body, la méthode getElementsByTagName() renvoie néanmoins un Array, dont le premier et seul élément est notre balise body. Vu que les indices des Array commence à 0, pour identifier notre élément body nous devons ajouter l'indice [0] à la méthode getElementsByTagName("body").

Le même principe concerne la manipulation 4., dans laquelle le Array contient par contre plusieurs éléments. Pour changer chaque élément, il faut par conséquent un cycle. Nous avons créé ce cycle à l'aide de la fonction for et nous avons déclaré en tant que fonction de sortie la propriété length de l'Array lui-même. Cette propriété identifie le nombre d'éléments présents dans l'Array.

Tester cet exemple

Ce type de manipulation est plutôt complexe, raison pour laquelle des bibliothèques JavaScript (e.g. jQuery) offrent des méthodes plus faciles pour accéder aux éléments du DOM.

Événements du DOM

Les événements du DOM permettent d'identifier l'interaction de l'utilisateur avec la page, par exemple à travers les mouvements de la souris, les touches du clavier, etc. Les événements concernent également les éléments eux-mêmes, par exemple dans le cas de l'objet window ou encore des éléments d'un formulaire.

L'événement onload

L'événement onload() est déclenché lorsqu'un élément (ou tout le DOM) a été téléchargé dans le navigateur web. Une notation qui est très utilisée et qui, par contre, nécessite de déclarer explicitement l'objet window concerne l'événement onload :

  • window.onload() : permet de déclencher du code une fois que la page a été chargée dans le navigateur. Il faut être attentif au fait que cette fonction peut être déclarée seulement une fois dans chaque page. Si plusieurs déclarations de window.onload sont disponibles dans la même page, seulement celle déclarée en dernière sera exécutée.
<script>
window.onload = alert("Je ne serais pas affiché");
window.onload = alert("Je serais affiché");
</script>

Un autre problématique relative à cette fonction concerne le fait que l'événement onload s'avère lorsque tous les éléments du DOM ont bien été chargés, y compris images, feuilles de style, etc. Ceci peut parfois retarder le déclenchement de l'événement et par conséquent toutes les éléments interactifs associés à cet événements ne seront pas disponibles.

L'événement onload() peut être également associé à d'autres éléments du DOM internes ou externes, comme par exemple les images, les iframes, etc.

Événements liés à la souris

Parmi les événements les plus utilisés dans l'interaction avec le DOM, il y a sans doute les événements liés aux mouvements et clicks de la souris. Voici une liste non exhaustive de ces événements :

  • click : l'événement est déclenché avec un click de la souris
  • mouseover : l'événement est déclenché lorsque la souris passe sur l'élément
  • mouseout : l'événement est déclenché lorsque la souris quitte un élément

Pour attribuer un événement à un élément il faut procéder ainsi :

  1. Identifier l'élément dans la structure du DOM (voir plus haut dans cette page)
  2. Spécifier un événement déclencheur à travers une des notations disponibles (e.g. document.getElementById("mon-bouton").onclick)
  3. Associer à cet événement un "event handler" (gestionnaire d'événement), c'est-à-dire le processus (normalement une fonction) qui doit se mettre en marche lorsque l'événement se produit

Il y a deux manières d'associer un événement à un élément :

  • Utiliser la propriété de l'événement qui se compose de "on" + événement (élément.onclick, élément.onmouseover, élément.onmouseut, ...) à la quelle on associe une fonction :
    • élément.onévénement = function () { ... }
  • Utiliser la méthode addEventListener qui prévoit deux arguments : l'événement et la fonction à exécuter :
    • élément.addEventListener(événement, fonction)

Le gestionnaire d'événement peut être une fonction déjà définie ou anonyme. Il faut cependant faire attention au fait qu'un gestionnaire d'événement est une référence à la fonction et non pas l'exécution de la fonction elle-même. En d'autres termes, il ne faut pas utiliser les parenthèses dans un gestionnaire d'événement :

function faireQuelqueChose() {
    //code
}
mon-element.mon-evenement = faireQuelqueChose; //OK!
mon-element.mon-evenement = faireQuelqueChose(); //Faux, de cette manière la fonction sera exécutée de toute manière, sans attendre l'événement déclencheur

Veuillez par contre noter que si l'on associe comme gestionnaire une méthode d'un objet, alors il faudra de toute manière insérer les parenthèses.

var o = {}:
o.faireQuelqueChose = function () {
  //code
}
mon-element.mon-evenement = o.faireQuelqueChose; //Faux
mon-element.mon-evenement = o.faireQuelqueChose(); //OK!

On peut également utiliser une fonction anonyme en tant que gestionnaire d'événement :

mon-element.mon-evenement = function() {
    console.log("L'événement a eu lieu");
}

Enfin, il est possible d'utiliser la méthodeélément.addEventListener(événement, gestionnaire) au lieu de la notation élément.événement = gestionnaire. Cette méthode à l'avantage de pouvoir s'ajouter à des gestionnaires d'événements déjà déclarés sur le même élément, sans les annuler (mais ne s'applique pas à window.onload). Voici un exemple pour illustrer ce principe qui se réfère au click sur un bouton :

<button id="myBtn">Button</button>
<script>
var myBtn = document.getElementById("myBtn");

//1. Utilisation de onclick
myBtn.onclick = function () {
  console.log("Événement 1");
}
myBtn.onclick = function () {
  console.log("Événement 2");
}

//-> Si on click sur myBtn, on verra dans la console seulement "Événement 2";

//2. Utilisation de addEventListener
myBtn.addEventListener("click", function () {
  console.log("Événement 1");
});
myBtn.addEventListener("click", function () {
  console.log("Événement 2");
});

//-> Si on click sur myBtn, cette fois-ci, on verra dans la console les deux messages.
</script>

Voici un exemple avec des commentaires pour résumer les différentes utilisations des événements liés à la souris :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - événements liés à la souris</title>
</head>
<body>
  <h1>JavaScript - événements liés à la souris</h1>
  <button id="mon-bouton">Cliquez ici</button>
  <span id="feedback"></span>
  <script>
   //Déclarer une fonction en cas d'événement click
   function showFeedbackClick() {
     document.getElementById("feedback").innerHTML = "J'ai cliqué sur le bouton";
   }

   //Définir une fonction en cas d'événement mouseover
   function showFeedbackOver() {
     document.getElementById("feedback").innerHTML = "La souris se trouve sur le bouton";
   }

   //Identifier le bouton dans le DOM
   var monBouton = document.getElementById("mon-bouton");

   //Trois manières différentes d'associer une fonction à un événement :
   //1. Événement click avec association d'une fonction, sans ()!
   monBouton.onclick = showFeedbackClick
   //2. Événement mouseover avec méthode addEventListener();
   monBouton.addEventListener("mouseover", showFeedbackOver);
   //3. Événement mouseout avec fonction anonyme
   monBouton.onmouseout = function() {
     document.getElementById("feedback").innerHTML = "La souris n'est plus sur le bouton";
   }
  </script>
</body>
</html>

Tester cet exemple

Pour annuler un gestionnaire d'événement, il suffit de le redéclarer null sa propriété d'événement (e.g. mon-élément.mon-événement = null) ou d'utiliser la méthode élément.removeEventListener().

Il existe une méthode plus souple pour définir un gestionnaire d'événement et que l'on retrouve aussi dans ActionScript.

Dans l'exemple suivant,la fonction start() sera exécutée dès que la page charge, ceci à cause de l'instruction window.onload = start; qui associe à l'événement "onload" le nom d'une fonction qu'il faut exécuter. Rien de neuf. Par contre, la gestion du 2ème événement se fait différemment.

<!DOCTYPE html>
<html>
   <head>
      <title>Event handling</title>
      <script type = "text/javascript">
         window.onload = start;
         // var my_para_button  ="";

	 function start()  {
	   // put an event handler on the div box
	   var my_para_button = document.getElementById("box");
	   my_para_button = addEventListener("click", modifyText);
         }

	 function modifyText() {
	   // get the box
	   var my_content = document.getElementById("content");
	   my_content.innerHTML = "That was so good";
	 }
      </script>
   </head>
   <body>
      <div id="box">
         <p style="background-color:yellow" id="content">CLICK ME !</p>
      </div>
   </body>
</html>

Source: http://tecfa.unige.ch/guides/js/ex-intro/event-handler.html

La fonction start ajoute un gestionnaire d’événement au bouton my_para_button en utilisant la méthode addEventListener ("click", modifyText); . Le premier argument, "click", identifie le type d’événement, et le deuxième donne le nom de la fonction.

L'élément this dans le DOM

Lorsqu'une fonction est associée à un élément du DOM, cet élément est disponible à l'intérieur de la fonction elle-même, à travers l'élément this. Ceci permet de ne pas avoir à identifier à nouveau l'élément dans le DOM. Voici un exemple qui modifie le label d'un bouton et le désactive après le click :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - this</title>
</head>
<body>
  <h1>JavaScript - this</h1>
  <button id="mon-bouton">Cliquez ici</button>
  <script>
    var monBouton = document.getElementById("mon-bouton");
    monBouton.onclick = function() {
      //Changer le label du bouton
      this.innerHTML = "J'ai cliquez sur le bouton";
      //Désactiver le bouton
      this.disabled = "disabled";
    } 
  </script>
</body>
</html>

L'élément this peut être très utile lorsqu'on genère plusieurs éléments dynamiquement pour associer un comportement à chaque élément. Voici un exemple similaire au précédent, mais dans lequel 5 boutons sont créés avec la fonction document.createElement("button"). Chaque bouton créé est associé ensuite à un événement de type onclick, à l'intérieur du quel on fait référence au bouton avec l'élément this :

var list = document.getElementById("btnList");
for(var i = 1; i <= 5; i++) {
  var btn = document.createElement("button");
  btn.innerText = "Cliquez sur le bouton " + i;
  btn.onclick = function () {
    this.innerText = "J'ai cliqué sur ce bouton";
    this.disabled = "disabled";
  }
  list.appendChild(btn);
}

Tester cet exemple et l'exemple précédent

JavaScript et CSS

Utiliser les propriétés de style

Javascript permet de modifier non seulement la structure du DOM, mais également les propriétés de style des éléments. Il est possible de modifier toutes les déclarations de style disponibles dans un fichier CSS à travers la notation :

élément.style.propriété = "nouvelle valeur";

Par exemple le code suivant modifie la couleur du texte d'un élément du DOM avec id="mon-paragraphe" :

document.getElementById("mon-paragraphe").style.color = "#F00";

Les changements de style peuvent être appliqués à tout moment dans le code et être donc associés, par exemple, à des événements (voir plus haut dans la page).

Utiliser les classes

JavaScript permet également de manipuler les noms de class des éléments. La manière la plus simple consiste à utiliser la propriété className pour lire ou définir la class d'un élément :

//Lire
var maClasse = élément.className; // --> e.g. active
//Définir
élément.className = 'active'

Il faut noter que la propriété className se réfère à tout le l'attribut HTML. Voici un élément HTML qui a plusieurs classes :

<div id="myDiv" class="class1 class2 class3">Mon div</div>

Et voici le résultat de quelques opérations avec JavaScript

var myDiv = document.getElementById("myDiv");
var classes = myDiv.className; // --> class1 class2 class3
//Ajouter une quatrième class
myDiv.className = classes + " class4"; // --> class1 class2 class3 class4
//Remplacer avec une seule class
myDiv.className = "class99"; --> class99

Pour faciliter la gestion de plusieurs classes sur le même élément, JavaScript met à disposition la propriété classList qui possède plusieurs méthodes (voir la liste complète) parmi lesquelles on trouve :

  • élément.classList.add(class, [class]) : permet d'ajouter une ou plusieurs nouvelles classes à l'élément
  • élément.classList.remove(class, [class]) : permet d'enlever une ou plusieurs classes à l'élément

Les deux codes suivants sont donc équivalents :

var myDiv = document.getElementById("myDiv");

//Avec className
var classes = myDiv.className; // --> class1 class2 class3
myDiv.className = classes + " class4"; // --> class1 class2 class3 class4

//Avec classList
myDiv.classList.add("class4"); // --> class1 class2 class3 class4

Une autre méthode utile associée à la propriété classList est la méthode toggle() qui :

  1. Ajoute une classe si la classe n'est pas associée à l'élément
  2. Enlève une classe si la classe est déjà associée à l'élément

Tester un exemple

JavaScript et les formulaires

Même si JavaScript ne se limite plus simplement à ces tâches, la manipulation des formulaires et des éléments des formulaires (e.g. champs de texte, etc.) restent des fonctionnalités très utilisées (et utiles). JavaScript peut en effet identifier le contenu des éléments des formulaires et utiliser se contenu dans sa logique de programmation pour apporter des changements à la page. Par exemple la propriété .value permet d'identifier le contenu d'un champ de texte :

var maValeur = document.getElementById("mon-champ-de-texte").value;

Cette notation, comme toute propriété, peut être utilisé aussi pour modifier le contenu d'un champ.

window.onload = function() {
    document.getElementById("mon-champ-de-texte").value = "Nouvelle valeur";
}

Voici un exemple qui utilise l'événement onchange pour suggérer une valeur combiné du prénom et nom d'une personne. Si le champ complet est modifié, néanmoins, aucune suggestion ne sera plus faite.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - formulaires</title>
</head>
<body>
<h1>JavaScript - formulaires</h1>
Prénom : <input type="text" id="prenom"><br>
Nom : <input type="text" id="nom"><br>
Nom complet : <input type="text" id="nom-complet"><br>
<script>
  var prenom = document.getElementById("prenom");
  var nom = document.getElementById("nom");
  var nomComplet = document.getElementById("nom-complet");
  function suggererNomComplet() {
    nomComplet.value = nom.value + ", " + prenom.value;
  }
  prenom.onchange = suggererNomComplet;
  nom.onchange = suggererNomComplet;
  nomComplet.onchange = function() {
    prenom.onchange = null;
    nom.onchange = null;
  }
</script>
</body>
</html>

Tester cet exemple

Validation des formulaires

Un autre cadre d'utilisation de JavaScript concerne la validation des formulaires avant qu'ils soient soumis au serveur (i.e. avec actualisation de la page). Cette fonction est désormais partiellement prise en charge par les attributs HTML5 tels que "required", mais il y néanmoins des validations plus complexes qui nécessitent du codage JavaScript.

Dans la structure du DOM, JavaScript peut identifier des champs d'un formulaire de plusieurs manières. On peut utiliser la méthode getElementById() et attribuer à chaque champ un id univoque, ce qui est probablement la manière plus sûre. Sinon, JavaScript identifie les formulaires et ses champs à travers un Array qui se construit sur l'attribut name du formulaire et des champs :

 <form name="mon-formulaire">
     <input type="texte" name="mon-champ1">
     <input type="texte" name="mon-champ2">
 </form>

Le form peut être identifié à travers la notation document.forms['mon-formulaire'] tandis que les champs respectivement avec :

  • document.forms['mon-formulaire']['mon-champ1']
  • document.forms['mon-formulaire']['mon-champ2'].

Il est également possible d'utiliser la notation "par point", au lieu des parenthèses carrées, si le nom du champ respecte la notation correcte pour les variables JavaScript.

Voici un simple exemple de validation pour montrer brièvement le mécanisme. Le code JavaScript contrôle que le champ email ne soit pas vide et que les conditions ont été acceptées à travers le checkbox.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - formulaires</title>
</head>
<body>
<h1>JavaScript - formulaires</h1>
<form name="mon-formulaire">
  Email : <input name="email" type="text"><br>
  <input type="checkbox" name="conditions"> J'accepte les conditions d'inscription<br>
  <input type="submit" value="Envoyer">
</form>
<script>
  var monForm = document.forms["mon-formulaire"];
  var monEmail = monForm["email"];
  var mesConditions = monForm["conditions"];
  monForm.onsubmit = function() { 
    if (monEmail.value !== "" && mesConditions.checked) {
      //Le formulaire sera soumis au serveur et la page actualisée
      return true; 
    } else {
      window.alert("Vous devez insérer votre email et accepter les conditions");
      //Le retour false fait ainsi que le formualire ne soit pas soumis et la page pas actualisée
      return false;
    }
  }
</script>
</body>
</html>

La sécurité avec JavaScript

La sécurité en JavaScript n'est pas à négliger car de nombreux exploits existent et sont assez facilement mis en place. Avant de commencer à lire ce qui suit, il est important de savoir que le JavaScript est interprété du coté de la machine du client (et non pas du coté du serveur).

Pourquoi il ne faut pas faire confiance à Javascript si vous êtes propriétaire d’un site web

Pour comprendre, il suffit de regarder cet exemple qui peut être trouvé sur le site de certains novices.

Exemple :

  function Login(){
            var password=document.login.password.value;
            if (password=="kztYq8") {
                window.location="bravo.htm";
            }
            else
            {
                window.location="dommage.htm";
            }
        }

Vous l'aurez compris, le mot de passe est défini en clair dans le code source de la page. Tout le monde y a accès. L'URL censée être protégée par le mot de passe est aussi disponible et accessible sans le mot de passe! Ayez toujours en tête que ce que vous écrivez en javascript est accessible à tout le monde.

Vérifier du côté client et du côté serveur

Ce qu'on a vérifié du coté client avec le JavaScript n'est pas fiable et doit être revérifié du coté serveur (avec du PHP par exemple). En effet, en désactivant simplement le JavaScript, on peut passer outre les contrôles d'un formulaire.

Attaques de Cross-site scripting (XSS)

Lors de la création d'une application ou d'un site avec JavaScript, il faut savoir que les attaques XSS existent et sont encore couramment utilisées. En résumé, l'attaque consiste à injecter des scripts dans la réponse d'une application, ce qui permet de récupérer les données sensibles de l'application et de les envoyer sur le serveur de la personne qui est à l'origine de l'attaque. Il existe deux types d'attaque XSS:

La reflectected XSS (non permanente) : L'attaquant injecte des scripts dans une application web pour que ceux-ci soient exécutés du coté client. L'attaque n'est pas stockée dans l'application et ne laisse aucune trace sur le serveur. Pour exploiter cette faille (XSS), l'ingénierie sociale doit être utilisée afin de tromper la "future" victime. L'attaquant va fournir une URL piégée à sa victime (via mail par exemple), lorsque la victime clique sur l'URL piégée, une requête contenant du code malicieux (scripts) est envoyé vers le serveur (officiel). Le code malveillant va alors s'exécuter sur la page renvoyé par le serveur (officiel), ce qui donne à l'attaquant le contrôle dessus. Celui-ci pourra ensuite, à partir de l'application, récupérer des données sur la victime, comme par exemple sa session ou ses cookies et les recevoir directement sur son serveur. Cela lui permettra de réaliser des actions au nom de l'utilisateur ou de lui voler des informations privées.

Exemple vidéo (anglais) : ICI

La persistent XSS (permanente) : Contrairement au premier type d'attaque, celle-ci consiste à injecter le code malicieux directement dans le système de stockage de l'application Web. Pour que la faille puisse être exploitée, l'application doit générer ses réponses via ces données stockées. Elle est souvent utilisée sur des forums qui sont mal sécurisés. Ceux-ci stockent les messages des utilisateurs dans des bases de donnée. Si un message contient un code malicieux, à chaque fois qu'un utilisateur affichera la page du forum contenant le message qui présente le code malicieux, celui-ci sera exécuté. Cette attaque est donc beaucoup plus dévastatrice puisqu'elle touche potentiellement tous les utilisateurs.

Exemple vidéo (anglais) : ICI

Comment se protéger contre les attaques XSS

Il existe plusieurs moyens de se protéger, la NSA a d'ailleurs rédigé un bon document à ce propos.

Afin d'éviter que des personnes malveillantes puissent injecter du code malveillant, les administrateurs réseaux doivent traiter les informations que les personnes envoient, une fois qu'elles sont parvenues au serveur et les retraiter lors de leur envoi au navigateur. Des fonctions PHP existent afin de traiter les données envoyées via JavaScript comme "htmlentities", qui convertit tous les caractères éligibles en entités HTML et strip_tags, qui suppriment les balises HTML et PHP d'une chaîne. L'une dans l'autre permet déjà une protection de base efficace (mais pas infaillible) contre ce genre d'attaque qui exploite le JavaScript. Des mesures supplémentaires peuvent être mises en place comme l'utilisation de pare-feux applicatifs qui détectent les informations suspectes envoyées au serveur. Du coté des utilisateurs, il ne faut jamais cliquer sur un lien dont la provenance est douteuse et toujours accéder aux sites via l'URL officielle. Ils peuvent aussi utiliser des extensions comme par exemple "NoScript" sur Firefox, qui offre une bonne protection de base contre ce genre de vulnérabilité.

Références