Accueil
Mes tutoriels sur la programmation


Tutoriel JavaScript & jQuery - sommaire

Vous pouvez me contacter via Facebook (questions, critiques constructives) : page facebook relative à mon site

JavaScript : compléments sur le langage

Où placer le conteneur SCRIPT dans une page ?

Le code JavaScript interne ou le lien vers du code JavaScript externe doit être à l'intérieur du conteneur SCRIPT.
Il peut y avoir plusieurs conteneurs SCRIPT dans une même page.

Si lien vers du code JavaScript externe. La syntaxe est alors :
<script src = "chemin relatif vers le fichier JS" ></script>
Le code JavaScript externe est dans un fichier qui a pour extension .js

Mais où placer le OU les conteneurs SCRIPT ? A quel endroit dans la page ?

Prenons un exemple. Nous voulons un script qui permet de modifier la couleur de texte des balises H1 et P de la page : vert ou rouge ou encore bleu selon le boutonde commande cliqué.

Le code HTML de la page(extrait)

... <body> <h1>Modification d'une propriété CSS pour des éléments de la page</h1> <p>Blabla ... <br>Blabla ... <br>Blabla ... </p> <button id = 'vert'>Couleur de texte : vert </button> <button id = 'rouge'>Couleur de texte : rouge </button> <button id = 'bleu'>Couleur de texte : bleu </button> ...

Le code JavaScript

Première technique qui bugue

Le conteneur SCRIPT est dans la partie HEAD de la page c'est à dire avant la balise fermante </head> .

Le script dans la partie HEAD (extrait) :

	var titre = document.querySelector('h1') ; 
	var texte = document.querySelector('p') ; 
	
	document.querySelector('#vert').onclick = 
		function() { 	titre.style.color = 'green'; texte.style.color = 'green'; }
	document.querySelector('#rouge').onclick = 
		function() { titre.style.color = 'red'; texte.style.color = 'red'; }
	document.querySelector('#bleu').onclick = 
		function() { 	titre.style.color = 'blue'; texte.style.color = 'blue'; }

Ce code plante !
La console JavaScript indique une erreur pour la ligne 9 ( document.querySelector('#vert').onclick ...): "Cannot set property 'onclick' of null" !
Ce plantage est logique car le script (qui ici a pour objet de manipuler des noeuds du DOM) s'exécute alors que le DOM n'est pas encore construit! Donc pour JavaScript les noeuds identifiés "vert, rouge, bleu" n'existent pas encore !

Les solutions

Première solution : correcte mais un peu ancienne ...

Le script est toujours dans la partie HEAD mais il est inclus dans une fonction nommée, par exemple : change_couleur().
Extrait de la partie HEAD :

	function change_couleur()
	{
		var titre = document.querySelector('h1') ; 
		var texte = document.querySelector('p') ; 
		document.querySelector('#vert').onclick 
			= function() { 	titre.style.color = 'green'; texte.style.color = 'green'; }
		document.querySelector('#rouge').onclick 
			= function() { titre.style.color = 'red'; texte.style.color = 'red'; }
		document.querySelector('#bleu').onclick 
			= function() { 	titre.style.color = 'blue'; texte.style.color = 'blue'; }
	}

Code dans la partie BODY :

<body onload ="change_couleur()"> <h1>... ...

Donc la fonction JavaScript est chargée avant le code HTML mais il ne s'exécute que lorsque tout le DOM est construit.

Variante plus moderne

Plus aucune mention du JavaScript dans le code HTML !
Le code JavaScript (toujours dans la partie HEAD) est compris dans une fonction mais qui cette fois est anonyme !
Le code dans la partie HEAD (extrait) :

window.onload = function() 
{
		var titre = document.querySelector('h1') ; 
		var texte = document.querySelector('p') ; 
		document.querySelector('#vert').onclick = 
			function() { 	titre.style.color = 'green'; texte.style.color = 'green'; }
		document.querySelector('#rouge').onclick = 
			function() { titre.style.color = 'red'; texte.style.color = 'red'; }
		document.querySelector('#bleu').onclick = 
			function() { 	titre.style.color = 'blue'; texte.style.color = 'blue'; }
} // fin fonction 

Intérêt de cette solution : le JavaScript et le HTML sont bien séparés ; plus de mélange !

Troisième solution : celle que je conseille

Le conteneur SCRIPT est placé dans la partie BODY de la page mais après toute la description des éléments HTML donc juste avant la balise </body>.

Le code de la fin de page devient alors :

... <!-- dernier élément HTML--> <script> var titre = document.querySelector('h1') ; var texte = document.querySelector('p') ; document.querySelector('#vert').onclick = function() { titre.style.color = 'green'; texte.style.color = 'green'; } document.querySelector('#rouge').onclick = function() { titre.style.color = 'red'; texte.style.color = 'red'; } document.querySelector('#bleu').onclick = function() { titre.style.color = 'blue'; texte.style.color = 'blue'; } </script> </body></html>

On revient donc au code JavaScript qui "buggait" mais comme ce code est à un emplacement différent cette fois-ci ça marche "du feu de Dieu". En effet le script est désormais exécuté après la construction du DOM.

Si vous programmez en JS-jQuery il suffit de rajouter dans la partie HEAD un script qui charge la fameuse bibliothèque. On a alors deux scripts dans la page : un dans la partie HEAD et un autre dans la partie BODY.
On a donc une page qui a la structure suivante :

... <script src ="jquery.js">chargement de la librairie jQuery</script> </head> <body> <!--code HTML construisant le DOM initial --> <script> <!--script basé sur les fonctions haut niveau de jQuery--> </script> </body></html>

JavaScript : les pièges

Concaténer au lieu d'additionner

L'opérateur + signifie additionner mais aussi concaténer si l'un des valeurs est de type string.
Exemple de fonction :

function ftest() 
{
	var var1 = 12, var2 = 14, var3 = 'bonjour' ; 
	alert(var1 + var2); 
	alert(var1 + var3); 
}

Deux variables de type number et une troisième de type string.

La fonction retourne 26 et la chaine "12bonjour" donc addition dans le premier cas et concaténation dans le second.

Délimiter une chaine

Si une chaine contient le caractère apostrophe elle ne peut pas être délimitée par des guillemets simples mais par des guillemets doubles OU alors il faut "échapper" l'apostrophe dans la chaîne : faire précéder la guillemet simple par le caractère \

Affectation et égalité

Attention en JavaScript (comme dans beaucoup de langages) il y a un caractère pour l'opération d'affectation(=) et un autre pour l'égalité (==).
Ainsi pour affecter une valeur initiale à une variable il faut écrire, par exemple : X = parseInt(X)
Pour tester si une variable est égale à une certaine valeur il faut écrire, par exemple : if (X==400)

La syntaxe des propriétés de style

Toutes les propriétés CSS peuvent être utilisées dans un script mais parfois avec une syntaxe un peu différente.

En JavaScript il est interdit d'utiliser le tiret dans un mot car ce caractère signifie soustraction.

Imaginons que vous vouliez via le JavaScript changer la valeur de la propriété background-color d'un élément HTML référencé par la variable objet titre.
Syntaxe incorrecte : titre.style.background-color = 'yellow'
Syntaxe correcte : titre.style.backgroundColor = 'yellow' ;

La règle est simple : pour écrire dans un script une propriété de style il faut supprimer le tiret éventuel et remplacer la lettre qui suit par son équivalent en majuscule.

Simplifications syntaxiques

Il y a peut être deux instructions qui vous laissent dubitatif(ve) : x+=20 ; y+=15 ;
En effet au lieu d'écrire : x = x + 20 on peut écrire plus simplement : x+=20
De même au lieu de : x = x - 20 on peut écrire : x-=20
Et si vous voulez changer le signe de delta vous pouvez écrire: delta*=-1 qui remplace : delta = delta * -1

JavaScript : le mot magique 'this'

Exemple

Survolez successivement chaque image et observez !

Le code CSS et HTML correspondant

... <style> img {display : block ; margin :10px auto 10px auto ;} img.petit {width : 15% ; opacity : 0.5 ; box-shadow : -5px -5px 5px grey ; } img.grand {width : 30% ; opacity : 1 ; box-shadow : 10px -10px 10px grey ; } ... <body> ... <img src = '../images/toucan.jpg' class ='petit' onmouseover ="fgrand(this)" onmouseout ="fpetit(this)" /> <img src = '../images/tortue.jpg'class ='petit' onmouseover ="fgrand(this)" onmouseout ="fpetit(this)" /> <img src = '../images/foret.jpg' class ='petit' onmouseover ="fgrand(this)" onmouseout ="fpetit(this)" /> <img src = '../images/riviere.jpg'class ='petit' onmouseover ="fgrand(this)" onmouseout ="fpetit(this)" /> ...

CSS : on définit deux classes spécifiques aux images : petit et grand.

HTML : quatre images affectées de la classe petit c'est à dire des miniatures avec un ombrage (ombre projetée vers le haut gauche).
Pour chaque image on appelle la fonction fgrand sur l'événement onmouseover et la fonction fpetit sur l'événement onmouseout.
Remarquez qu'à chaque fois le paramètre passé est this.
this est un mot réservé de JavaScript très pratique. Il désigne l'élément HTML courant (ou actif).

Le mot "magique"this ne peut être utilisé que comme paramètre lors de l'appel de la fonction.

Le script

	function fpetit(image) {image.className ="petit" ; }
	function fgrand(image) {image.className ="grand" ; }

La fonction fpetit applique la classe petit à l'objet identifié image (image courante).
La fonction fgrand applique la classe grand à l'objet identifié image (image courante).

Appel des fonctions

Les techniques pour appeler une fonction JS sont nombreuses. Mais certaines sont meilleures que d'autres.
Certaines méthodes anciennes sont mêmes fortement déconseillées.

Appel des fonctions dans le code HTML

La fonction doit forcément être nommée !
Donc la structure de la fonction décrite dans le script doit être la suivante :

	function nomfonction()
	{
		instruction1 ; 
		instruction2 ; 
		...
		instruction n ;
	} // fin fonction

N'oubliez surtout pas le mot réservé function ainsi que la paire de parenthèses après le nom de la fonction m ême si il n'y a pas passage de paramètre.

Mais comment appeler cette fonction nommée ?

Il y a deux solutions : une mauvaise et une autre bonne !

Appel de la fonction avec la balise A

<a href ="javascript:nomfonction()">Cliquez ici</a>

Technique qui date des origines du JavaScript est qui fortement déconseillée.
La balise A doit être utilisée pour créer des liens et rien d'autres.

Emploi du gestionnaire d'évènements de HTML

La fonction est appelée via la balise début sur un événement toujours préfixé par "on".
On dit que l'on utilise les attributs événementiels de HTML.
Quelques exemples :

<body onload ="nomfonction()" ...> <select onchange="nomfonction()" ...> <button onclick ="nomfonction()" ...> <input type ="..." onfocus ="nomfonction()" ... /> <input type ="..." onblur ="nomfonction()" ... />

Cette solution présente un inconvénient. Elle suppose que la personne qui code en HTML connaisse aussi le JavaScript ...

Emploi du DOM

L'appel des fonctions est faite dans le script !

Dans le code HTML plus aucune référence au JavaScript. Ce qui facilite la division du travail dans le cadre de la production.
Autre avantage : il n'est plus nécessaire de nommer les fonctions. On peut utiliser des fonctions anonymes !

Il faut donc sélectionner des noeuds du DOM (éléments HTML ou SVG). Il faut donc utiliser une méthode de sélection de l'API DOM.

Emploi de la méthode document.getElementByID

C'est la méthode de sélection d'un noeud la plus connue.
Exemple :

HTML : <img id ="image1" src = ... /> <img id ="image2" src = ... /> Le script : document.getElementById("image1").onmouseover = function() { this.style.opacity = "1" ; this.style.height = "100px";} document.getElementById("image2").onmouseover = function() { this.style.opacity = "1" ; this.style.height = "100px";} ...

On utilise ici le mot magique this dans la fonction car les modifications portent sur l'objet sélectionné.

Emploi des nouveaux sélecteurs de l'objet document

La méthode getElementByID présente un inconvénient. Lors de l'écriture du HTML il faut idenfier chaque élément susceptible d'être manipulé par le JavaScript : donner à chaque élément un attribut ID.

Avec les nouveaux sélecteurs on peut écrire :

HTML : <img src = ... /> <img src = ... /> Script : document.querySelector('img').onclick = function() { this.style.opacity = "1" ; this.style.height = "100px";} document.querySelectorAll('img')[1].onclick = function() { this.style.opacity = "1" ; this.style.height = "100px";} ...

Remarque : dans la première ligne on aurait pu écrire : document.querySelectorAll('img')[0].onclick
L'emploi de ces nouveaux sélecteurs simplifie le code HTML (disparition de l'attribut ID).

Utiliser dans le script les évènements onclick, onchange, onmouseover, etc. C'est faire du DOM-0.

Utilisation du DOM-2

Si vous utilisez le gestionnaire d'évènements addEventListener vous faites du DOM-2.

Premier exemple

... <button>cliquez ici ! </button> <script> var bouton = document.querySelector('button'); bouton.addEventListener('click',function() {var vnom = prompt('tapez votre nom') ; alert("bonjour " + vnom );},false); ...

On suppose bien sûr que dans la page il n'y a qu'un élément de type BUTTON.

Observez bien le script. Il faut utiliser la méthode addEventListener avec trois arguments:

Exemple 2

L'emploi du DOM-2 est un peu plus compliqué. Mais il offre un gros avantage : possibilité de pouvoir associer à un même événement sur le même noeud plusieurs fonctions.

Et bien sûr (mais c'était déjà possible avec le DOM-0) il permet de manipuler l'objet "event".
C'est ce que je vais vous montrer dans l'exemple 2.
Sachez qu'il y a un élément "button" dans le code HTML.
Le script :

	var vnom,vprenom ; 
	var bouton = document.querySelector('button'); 
	bouton.addEventListener('click',function()
		{vnom = prompt('tapez votre nom') ;
		vprenom = prompt('tapez votre prénom') },false); 
	bouton.addEventListener('click',function() 
		{alert("bonjour " + vnom );
		alert("prénommé " + vprenom )},false); 
	bouton.addEventListener('click',f3,false) ; 
	function f3(event)
		{alert("type évènement : " + event.type) ; 
		alert("cible évènement : " + event.target);
		}
...

Remarquez que la fonction f3 est décrite à part.

Je pense que vous avez compris l'intérêt de l'emploi de addEventListener.
Supposons que l'on vous demande de rajouter des actions sur clic sur un noeud. Si vous n'utilisez pas le DOM ou simplement le DOM-0 vous êtes obligé de réécrire toute la fonction JavaScript. Tandis si vous employer le DOM-2 (c'est à dire addEventListener) il suffit de rajouter une fonction sur le même noeud pour le même événement. Pratique, n'est-ce pas ...