JavaScript : Manipuler le DOM

Sélectionner les noeuds du DOM (les éléments HTML)

Exemple à tester

Par défaut chaque image est une miniature transparente. Sur clic elle s'agrandit et devient opaque.

Vous devez donc manipuler via JavaScript ces trois images. Pour cela il faut les référencer dans le script.
Si vous avez quelques notions de JavaScript on vous a sans doute appris que pour référencer en JavaScript un noeud il fallait utiliser des méthodes de l'objet document : getElementById ou getElementsTagName.
Ces méthodes de sélection des noeuds du DOM sont obsolètes !

Ainsi la fameuse méthode getElementById présente un inconvénient : il faut adapter le code HTML en vue du traitement JavaScript : ajouter l'attribut id à tous les noeuds susceptibles d'être manipulés en JavaScript.

Le code - première solution

Utilisation de la vieille méthode getElementById.

Code CSS & HTML

<style> img {display : block ; width : 10% ; margin :10px auto 10px auto ; opacity : 0.4 ;} ... <img src = '../images/toucan.jpg' id ='image1'> <img src = '../images/tortue.jpg' id ='image2'> <img src = '../images/foret.jpg' id ='image3'>

Il faut obligatoirement ajouter un attribut id à chaque balise img !

Le code JavaScript

document.getElementById('image1').onclick = function() { this.style.opacity = "1" ; this.style.width = "20%";} document.getElementById('image2').onclick = function() { this.style.opacity = "1" ; this.style.width = "20%";} document.getElementById('image2').onclick = function() { this.style.opacity = "1" ; this.style.height = "20%";}

Le code - deuxième solution

Il faut mieux utiliser les nouvelles méthodes de sélection des noeuds : querySelector ou querySelectorAll

Le code CSS inchangé !

Code HTML

<img src = '../images/toucan.jpg' > <img src = '../images/tortue.jpg' > <img src = '../images/foret.jpg' >

Les attributs id ont disparu !

Le code JavaScript

document.querySelector('img').onclick = function() { this.style.opacity = "1" ; this.style.width = "20%";} document.querySelectorAll('img')[1].onclick = function() { this.style.opacity = "1" ; this.style.width = "20%";} document.querySelectorAll('img')[2].onclick = function() { this.style.opacity = "1" ; this.style.width = "20%";}

On a utilisé les deux nouvelles méthodes pour sélectionner les noeuds : querySelector et querySelectorAll.

document.querySelector('img') référence la première balise img.
On aurait pu écrire aussi : document.querySelectorAll('img')[0]

document.querySelectorAll('img')[1] référence la deuxième image.

Donc vous avez compris que la méthode querySelectorAll(sélecteur) référence un tableau d'éléments.
Pour que cette méthode ne référence qu'un noeud il faut utiliser la syntaxe : document.querySelectorAll(sélecteur)[indice].

Attention le premier élément à l'indice zéro !

Avec ces nouvelles méthodes de sélection des noeuds du DOM le paramètre n'est pas forcément une balise HTML (ou SVG) mais n'importe quel sélecteur CSS valide.

Ainsi en supposant que dans une page certains noeuds soient affectés de la classe special et qu'un autre noeud ait l'ID titre on pourrait écrire en JavaScript :
document.querySelector('.special') pour sélectionner le premier noeud affecté de la classe special.
document.querySelectorAll('.special')[1] pour sélectionner le deuxième noeud affecté de la classe special.
document.querySelector('#titre') pour sélectionner le noeud ayant l'id titre.

Il s'agit donc de méthodes qui sont très souples et simples puis quelque soit la nature de l'arguement (balise, classe ou ID) c'est toujours la même syntaxe.

Et surtout l'emploi de ces nouvelles méthodes dans le script simplifient le code HTML ; l'attribut ID devient le plus souvent inutile. Donc le développeur web qui écrit le HTML n'a plus à se préoccuper du traitement JavaScript.

Modifier le contenu des noeuds

Pour modifier le contenu d'un élément il faut utiliser les propriétés textContent ou innerHTML. Exemple à tester

Le code HTML de l'exemple

... <h1>Modification des contenus des noeuds</h1> <h2>Le pays d'Ardres</h2> <figure> <img src = '../images/ardres.jpg' width ="100%"> <figcaption>Le lac d'Ardres en hiver</figcaption> </figure> <p>Ardres est connu pour son lac qui est un havre de tranquillité.</p> <img src ='../images/francais.jpg' class ='miniature' title = 'version française'> <img src ='../images/anglais.jpg' class ='miniature'title = 'version anglaise'> ...

Le script

// création de variables objet 
	titre = document.querySelector('h2') ; // titre référence la balise h2
	legende_image = document.querySelector('figcaption') ; // legende_image référence la balise figcaption
	texte = document.querySelector('p') ; // texte référence la balise P
	
// gestion événements 
	document.querySelectorAll('img')[1].onclick = fran; // appel de la fonction fran si clic sur la deuxième image
	document.querySelectorAll('img')[2].onclick = angl ; // appel de la fonction angl si clic sur la troisième image
	function fran()
	{ 		// page en français
		titre.textContent = "Le pays d'Ardres" ; 
		texte.innerHTML = "Ardres est connu pour son lac qui est un havre de tranquillité."; 
		legende_image.textContent = "Le lac d'Ardres en hiver"; 
	} // fin fonction 
	function angl() 
	{		// page en anglais
		titre.textContent = "Country of Ardres" ; 
		texte.innerHTML = "Ardres is known for his lake which is a place of tranquillity."; 
		legende_image.textContent = "The lac of Ardres during winter"; 
	} // fin fonction 

La propriété innerHTML est plus puissante que textContent car elle permet d'insérer du texte et du balisage.
Ici je mets en gras le texte (insertion de la balise B).

Modifier les valeurs d'attributs

Manipuler le DOM c'est aussi pouvoir modifier les valeurs des attributs.
Mais avant de les modifier il faut souvent les récupérer ces valeurs ...

Récupération des valeurs des attributs d'un noeud

Le code de la page (extraits)

... <style> .ombre {box-shadow : 5px 5px 5px grey ; } </style> </head> <body> <h1>Afficher les valeurs de tous les attributs d'une image </h1> <img src ='../images/toucan.jpg' alt ='toucan' title ='le toucan' width = '300' height = '200' class = 'ombre'> <script> var vinfo ; // première solution : noeud.getAttribute(attribut) var image = document.querySelector('img') ; vinfo = image.getAttribute('width'); alert('largeur image : ' + vinfo); vinfo = image.getAttribute('height'); alert('hauteur image: ' + vinfo); vinfo =image.getAttribute('src'); alert('source image: ' + vinfo); vinfo =image.getAttribute('alt'); alert('texte alternatif: ' + vinfo); vinfo =image.getAttribute('title'); alert('info bulle: ' + vinfo); vinfo =image.getAttribute('class'); alert('classe affectée : ' + vinfo) ; // deuxième solution : noeud.attribut alert('largeur image : ' + image.width); alert('hauteur image : ' + image.height); alert('source image : ' + image.src); alert('texte alternatif: ' + image.alt); alert('info bulle: ' + image.title); alert('classe affectée: ' + image.className); </script> </body> ... Testez cette page !

Commentaire du code

Ce script affiche deux fois la valeur de chacun des six attributs de l'image unique de la page.

Attention il y a cependant une différence avec l'attribut src qui indique le chemin relatif avec la syntaxe image.getAttribute('src') et indique le chemin absolu avec la syntaxe image.src

Pour récupérer le nom de la classe affectée à un noeud il faut argumenter la méthode getAttribute avec le mot class ; ce qui est tout à fait logique. Par contre avec la syntaxe simplifiée il faut utiliser le mot className ce qui l'est moins ...

Modifier les valeurs des attributs d'un noeud

Dans cet exemple je modifie les attributs width et height d'un noeud (une image).

Le code de la page (extrait)

... <body> <h1>Modification de deux attributs d'un noeud : width et height</h1> <p>Le rapport largeur / hauteur est toujours égal à 3/2</h1> <img src ='../images/toucan.jpg ' width = '300' height ='200' style = 'margin : auto ;'> <table> <caption>Faites varier la taille de l'image</caption> <tr><th><button id = 'plus'>+</button></th><th> <button id = 'moins'>-</button></th></tr> </table> <script> var image = document.querySelector('img'); var vlargeur = 300; var vhauteur; document.querySelector('#plus').onclick = function() { vlargeur +=9 ; vhauteur = vlargeur *2 /3 ; image.width = vlargeur ; image.height = vhauteur ; } document.querySelector('#moins').onclick = function() { vlargeur -=9 ; vhauteur = vlargeur *2 /3 ; image.setAttribute('width',vlargeur) ; image.setAttribute('height',vhauteur) ; } </script> </body> ... Testez l'exemple !

Commentaire

Il y a une image redimensionnée par rapport à sa taille d'origine grâce aux attributs width et height.
Il y a un clavier tactile obtenu grâce à un tableau HTML. Ce tableau comprend dans chaque cellule un bouton. Un bouton est identifié plus et un autre moins.
Si vous cliquez sur le bouton plus vous augmentez la taille de l'image et si vous cliquez sur moins vous réduisez sa taille.

Dans la première fonction on utilise la syntaxe simplifiée noeud.attribut= nouvelle valeur et dans la deuxième fonction on utilise la méthode setAttribute.
Donc la syntaxe est : noeud.setAttribute('attribut',nouvelle valeur )

Modifier les propriétés de style

Manipuler le DOM c'est aussi modifier les valeurs des propriétés de style.
Mais avant de les modifier il faut souvent les récupérer ces valeurs ...

La récupération des valeurs des propriétés de style

Dans certains ouvrages vous pourrez lire que pour récupérer la valeur d'une propriété de style d'un noeud il faut utiliser la syntaxe : noeud.style.propriété

N'utilisez surtout pas cette syntaxe ! En effet ça ne marche que si les propriétés de style du noeud sont définies dans la balise via l'attribut style. Avec cette syntaxe il n'est donc impossible de récupérer une propriété du noeud définie dans le cadre d'une feuille de style(interne ou externe).

Le code de l'exemple

... <link href ="../style.css" rel = "stylesheet" > <style> h1 {background-color : yellow ; height : 50px ; line-height : 50px ; border : 2px solid red ; } </style> </head> <body> <h1>Titre de la page</h1> <img src ='../images/toucan.jpg' width = '200' style = "margin : 20px auto 20px auto ; opacity : 0.5; border : 1px solid black " > <button>infos sur mise en forme image</button> <button>infos sur mise en forme titre </button> <script> // variables objet globales pour référence deux noeuds. var titre = document.querySelector('h1') ; var image = document.querySelector('img'); document.querySelector('button').onclick = function() { var vinfo = getComputedStyle(image).opacity ; alert("valeur de opacity : " + vinfo); var vinfo = getComputedStyle(image).border ; alert("valeur de border : " + vinfo); var vinfo = getComputedStyle(image).marginLeft ; alert("valeur de margin left : " + vinfo); var vinfo = getComputedStyle(image).marginTop ; alert("valeur de margin top : " + vinfo); var vinfo = getComputedStyle(image).display ; alert("valeur de display : " + vinfo); } document.querySelectorAll('button')[1].onclick = function() { vinfo = getComputedStyle(titre).backgroundColor ; alert("valeur de background-color : " + vinfo); vinfo = getComputedStyle(titre).height ; alert("valeur de height : " + vinfo); vinfo = getComputedStyle(titre).lineHeight ; alert("valeur de line-height : " + vinfo); vinfo = getComputedStyle(titre).border ; alert("valeur de border : " + vinfo); vinfo = getComputedStyle(titre).fontSize ; alert("valeur de font-size : " + vinfo ); vinfo = getComputedStyle(titre).marginTop ; alert("valeur de margin top : " + vinfo ); } </script>

Testez ce code !

Commentaire

J'ai utilisé la méthode getComputedStyle(noeud).propriété

Bien sûr je désigne par "noeud" la variable objet qui référence le noeud.

Vous pouvez remarquer que j'ai récupéré des valeurs de propriétés de style quelque soit l'endroit où elles sont définies.
Ainsi pour le noeud image la propriété opacity est définie dans la balise mais la propriété display est définie dans la feuille de style externe ("style.css"). Et pour le noeud titre les propriétés sont définies dans la feuille de style interne.

Attention vous devez utiliser la syntaxe JavaScript des propriétés de style (et non pas la syntaxe CSS) !

Il y a une différence lorsque la propriété est un mot composé.
En effet en JavaScript les tirets sont interdits(signifie "moins").
Donc pour passer de la syntaxe CSS à la syntaxe JS il suffit de supprimer le tiret et de remplacer la lettre qui suit par son équivalent en majuscule.

Prenons quelques exemples.

propriété de formatagesyntaxe CSSsyntaxe JS
couleur de fondbackground-colorbackgroundColor
bordure (méga propriété)borderborder
hauteur de ligneline-heightlineHeight
marges externesmarginmargin

Modifier les valeurs des propriétés de style

Le code de l'exemple :

... <style> img{margin : 20px auto 20px auto ; opacity : 0.1;} </style> </head> <body> <h1>Modification d'une propriété de mise en forme</h1> <p>La valeur de la propriété de style <b>opacity</b> augmente ou diminue selon que l'on clique sur + ou sur - </p> <img width = '200' src ='../images/toucan.jpg' > <table> <caption>Faites varier l'opacité de l'image</caption> <tr><th><button id = 'plus'>+</button></th><th> <button id = 'moins'>-</button></th></tr> </table> <script> var image = document.querySelector('img'); var vopacite = getComputedStyle(image).opacity ; // récupération de la valeur actuelle de la propriété opacity alert("type de la valeur :" + typeof(vopacite)) ; // attention la valeur retournée par getComputedStyle est de type string var vopacite = parseFloat(vopacite); // conversion d'une chaîne en réel document.querySelector('#plus').onclick = function() { vopacite +=0.1; image.style.opacity = vopacite ;} document.querySelector('#moins').onclick = function() { vopacite -=0.1; image.style.opacity = vopacite ;} </script> ...
Testez !

La page comprend une image pratiquement transparente (opacity = 0,1) et un clavier tactile.
Cette quasi transparence a été définie au niveau de la feuille de style interne.

Le script consiste à modifier la valeur de la propriété de style opacity.
Mais il faut d'abord récupérer la valeur initiale avec la méthode getComputedStyle (voir chapitre précédent) dans la variable vopacite.
Or la valeur récupérée est de type string comme l'indique la fonction typeof.
On ne peut pas incrémenter ou décrémenter directement une chaîne ! Donc il faut avant la convertir en réel avec la fonction parseFloat.
En cliquant sur le bouton plus l'image devient plus opaque puisque on incrémente vopacite .
En cliquant sur le bouton moins l'image devient plus transparente puisque on décrémente vopacite.

Pour changer la valeur d'une propriété de style vous pouvez toujours utiliser la syntaxe :
noeud.style.propriété = nouvelle valeur quelque soit l'endroit ou la propriété a été définie (avec l'attribut style ou dans une feuille de style interne ou externe.

Se déplacer dans le DOM

Manipuler le DOM c'est aussi pouvoir se déplacer dans l'arborescence ! Exemple à tester

Le code HTML de la page

... <body> <section style ="border :1px solid red"> <h1>Titre général</h1> <p>Corps de texte associé au titre général. <br>Blabla ... </p> <h2>Titre de niveau 2</h2> <p>Corps du texte associé au titre de niveau 2. <br>Blabla ...</p> <h2>Titre de niveau 2</h2> <p>Corps du texte associé au titre de niveau 2. <br>Blabla ...</p> </section> <button>Infos sur le parent de H1</button> <button>Infos sur les enfants de SECTION</button> ... <ul>La balise SECTION a 6 enfants : <li>une balise H1 <li>2 balises H2 <li>3 balises P </ul>

Le script

	document.querySelectorAll('button')[0].onclick = function() 
	{
		var enfant = document.querySelector('h1');
		var parent = enfant.parentNode ;
		alert('balise parente de H1 :' + parent.nodeName) ; 
	}
	document.querySelectorAll('button')[1].onclick = function() 
	{
		var parent = document.querySelector('section');
		var premier = parent.firstElementChild ; 
		alert('premier enfant de section' + premier.nodeName) ; 
		var dernier = parent.lastElementChild ; 
		alert('dernier enfant de section' + dernier.nodeName) ; 
		alert('contenu' + dernier.innerHTML); 
	}

La propriété parentNode pointe l'élément parent du noeud sélectionné.
La propriété nodeName le type de balise correspondante.

Les propriétés firstElementChild et lastElementChild pointent respectivement le premier élement enfant et le dernier élément enfant du parent.

Insérer des éléments dans la page

Manipuler le DOM c'est aussi créer de nouveaux éléments HTML Exemple à tester

Le code de la page

... <meta charset = 'utf-8'> <title>onglet à fermer</title> <meta name="viewport" content= "width=device-width, user-scalable=yes" /> <body> <section style ="border :1px solid red"> <h1>Titre général</h1> <p>Page très moche car aucun CSS !!! <br>Blabla ... </p> <h2>Titre de niveau 2</h2> <p>Corps du texte associé au titre de niveau 2. <br>Blabla ...</p> <h2>Titre de niveau 2</h2> <p>Corps du texte associé au titre de niveau 2. <br>Blabla ...</p> </section> <button>Créer un 'link' vers une feuille de style externe</button> <button>Insérer une image dans la page</button> ...

La page est très moche car il n'y a pas de CSS (pas de lien vers une feuille de style externe).

Le script

		document.querySelectorAll('button')[0].onclick = function() 
	{
		var lien =document.createElement('link');
		lien.href ="../style.css"; 
		lien.rel ="stylesheet";
		document.querySelector('head').appendChild(lien); 
		document.querySelector('p').texContent ="page désormais plus jolie" ; 
	}
	document.querySelectorAll('button')[1].onclick = function() 
	{
		var image =document.createElement('img');
		image.src ="../images/bikini.jpg";
		image.alt ="jolie fille en bikini";
		document.querySelector('section').appendChild(image); 
	}

Si clic sur le premier bouton création d'une balise LINK. Donc la page est beaucoup plus jolie !
Si clic sur deuxième bouton insertion dans la boîte SECTION d'une jolie image.
Dans les deux cas il faut d'abord créer un nouvel élément avec la méthode createElement(type de balise) puis il faut donner des attributs à cet élément et enfin il faut insérer l'élément avec la méthode appendChild.
La balise LINK est insérée dans HEAD et l'image est insérée dans SECTION.
Le nouvel élément est ajouté en dernier !
Retour menu