Accueil

Traduction

Tutoriel sur Javascript, Vue.js, jQuery.js & Node.js

Tutoriel JavaScript - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

Manipuler le DOM avec JavaScript

Ce chapitre est relativement long mais c'est logique car la modification du DOM est l'une des principales missions assignée à JavaScript.
Des effets de style sur l'élément survolé ou cliqué sont possibles via le CSS ; mais dès que vous voulez modifier le contenu initial d'un élément, modifier les attributs, rajouter ou supprimer des éléments, etc. il faut recourir à un script.

le DOM

Le DOM est une interface de programmation qui nous permet de manipuler le code HTML & CSS d’une page web de façon dynamique en utilisant le langage JavaScript.
Le DOM est créé automatiquement lors du chargement d’une page web par le navigateur.
Désormais tous les navigateurs génèrent le même DOM, ce qui n'était pas le cas à l'origine (d'où l'invention du framework jQuery ...)

On peut donc manipuler désormais le DOM en JS natif (sans recourir à jQuery). C'est ce que nous faisons dans ce chapitre.

Les noeuds du DOM

Tout dans une page web doit être considéré comme un noeud ("node" en anglais).
Le document HTML est un noeud, chaque élément HTML est un noeud, les attributs des balises sont des noeuds, le texte de chaque balise est aussi un noeud.

La structure DOM d'une page

Le code d'une page

Le DOM de cette page

Le DOM de cette page va être construit comme une hiérarchie de nœuds. On peut le représenter sous forme d'un arbre.
Sachez que la page HTML est le noeud le plus haut hiérarchiquement et appelé : DOCUMENT.
Toutes les balises doubles ou simples de la page constituent des noeuds de type ELEMENT (ou plus simplement élements).
Ainsi la balise double HTML est un noeud de type ELEMENT.

Le noeud HTML comprend deux "enfants" : HEAD et BODY. Pour ces deux "enfants" HTML est l'élément "parent".
L'élément HEAD contient à son tour deux enfants : TITLE et META. On peut dire aussi que TITLE et META ont pour "parent" HEAD.
L'élément BODY contient quatre enfants : H1 et trois balises P.

La structure DOM d'une page apparait dans l'onglet "éléments" de la console du navigateur.
L'interface DOM va nous permettre de manipuler les éléments du document pour le rendre dynamique.

Cibler un noeud de type élément

Avant de manipuler en JavaScript un élément HTML (une balise donc) il faut pouvoir le cibler.
Il existe plusieurs méthodes pour accéder à un élément HTML mais toutes ont un point commun : elles retournent un objet !
Donc la syntaxe générique est : variable = méthode de ciblage d'un élément HTML
Après cette instruction la variable créée n'est pas une variable simple (qui stocke une primitive) mais une variable objet qui référence dans le script un élément HTML du document.

Méthodes de sélection d'un élément ou d'une collection d'éléments

Il faut utiliser le DOM et en particulier les méthodes de l'objet document. Il faut distinguer les anciennes méthodes et les nouvelles introduites par HTML 5.

Pour les deux dernières méthodes, notez bien le mot "Elements" est au pluriel puisque la méthode peut retourner une collection de noeuds.

Ces deux nouvelles méthodes ont pour argument un sélecteur CSS.
Attention la première méthode retourne le premier élément correspondant au sélecteur CSS passé en paramètre.
La deuxième méthode retourne un tableau (array).

La méthode querySelector()

La méthode querySelectorAll()

Si vous voulez cibler la troisième balise P de la page et que cet élément n'a ni l'attribut ID ni l'attribut class comment faire ? Il suffit d'écrire : document.querySelectorAll('p')[2] . En effet le premier élément P à l'indice 0 dans l'objet array et donc le troisième a l'indice 2 dans le tableau.

Exemple

Thème : comment cibler une collection d'éléments via un script ?

Le code HTML de la page web

Le script associé

function f1()
{
	var paragraphes = document.querySelectorAll('p'); 
	// ou paragraphes = document.getElementsByTagName('p')
	for (element of paragraphes) {element.style.color ="red"; } 
}
function f2()
{
	var remarques = document.querySelectorAll('.rem'); 
	//ou remarques = document.getElementsByClassName('rem')
	for (element of remarques) {element.style.color ="green"; } 
}

Pour cibler une collection d'éléments de la page j'utilise la méthode querySelectorAll('sélecteur CSS') de l'objet document. Mais je vous montre en commentaire la solution ancienne correspondante.
Grâce à querySelectorAll() les variables paragraphes & remarques sont des tableaux (arrays).
Un objet array (tableau) peut être parcouru par la boucle for ... of ... .
Notez aussi la syntaxe pour modifier la valeur d'une propriété CSS : élément.style.propriété = "nouvelle valeur"

Le rendu

Récupérer des informations sur les éléments

Un élément se caractérise par un contenu (texte et balisage), des attributs (src, class, alt, title, style, etc.) et des propriétés CSS.

La récupération d'un paramètre d'un élément est souvent un préalable à sa modification.
Un seul exemple : si vous voulez augmenter l'opacité d'une image, il faut récupérer la valeur initiale de la propriété opacity puis incrémenter cette valeur.

Récupération du contenu d'un élément (texte et balisage)

Code HTML de la page

Le script

document.querySelector('button').onclick = function()
{
	titre = document.querySelector('h1') ; 
	para = document.querySelector('p') ; 
	
	alert("Contenu et balisage du titre : " + titre.outerHTML);
	alert("Texte de titre  : " +  titre.innerText); 
	
	alert("Contenu et balisage du titre : " + para.outerHTML); 
	alert("Texte de titre  : " + para.innerText); 
	
	image = document.querySelector('img');
	alert("Attribut alt de l'image ? " +  image.hasAttribute('alt')); 
	alert("Attribut src de l'image ? " + image.hasAttribute('src')); 
}

titre référence la première balise H1 de la page.
para référence la première (et unique) balise P de la page.
image référence l'image unique de la page.

Pour savoir si l'image dispose de certains attributs j'ai utilisé une instruction basée sur la méthode élément.hasAttribute('attribut'). Cette méthode retourne true / false.

Le rendu du code dans un iframe

Observez bien la différence entre les propriétés outerHTML & innerText.

Récupération des valeurs des attributs

On veut récupérer les valeurs des différents attributs d'un élément IMG.

Le code de la page (extraits)

Le rendu du code :

Récupération des propriétés de style d'un élément

Dans certains ouvrages on peut lire que pour récupérer la valeur d'une propriété CSS d'un élément on peut utiliser la syntaxe : élément.style.propriété

N'utilisez surtout pas cette syntaxe !
En effet ça fonctionne mais à condition que les propriétés de style de l'élément soient "en ligne" (via l'attribut style). Donc il n'est donc pas possible de récupérer une propriété de l'élément définie au niveau d'une feuille de style (interne ou externe).

Le code HTML de l'exemple

Lien vers une feuille de style externe qui formate les balises H1 et définit la classe "centre".
Pour info extrait de cette feuille de style externe :

...
img.centre {display : block ; margin : 10px auto ; width : 60%; }
...

Le script

	var image = document.querySelector('img'); 
	
	image.onclick = function() 
	{
		alert("infos sur les propriétés de l'image"); 
		alert("valeur de opacity : " + getComputedStyle(image).opacity); 
		alert("valeur de width : " + getComputedStyle(image).width); 
		alert("valeur de height : " + getComputedStyle(image).height);
		alert("valeur de display : " + getComputedStyle(image).display); 
		alert("valeur de margin : " + getComputedStyle(image).margin); 	
		alert("valeur de margin : "+ image.style.margin)
	}

Le rendu du code

La dernière instruction ne retourne aucune information (car la propriété margin n'est pas définie en ligne) alors que l'avant dernière instruction fonctionne !
Il faut donc utiliser systématiquement la méthode getComputed(élément).propriété qui fonctionne quelque soit l'emplacement de la règle de style.

À la question quelle largeur ? le script ne retourne pas 60% mais une largeur en pixels en fonction de la largeur de la fenêtre ; même remarque pour les marges gauche et droite.

Attention, pour les noms des propriétés de style, vous devez utiliser la syntaxe JS. En effet en JavaScript le tiret milieu est un opérateur (soustraction) et ne peut être utilisé pour désigner une variable, une propriété, etc. Donc pour passer du nom CSS de la propriété au nom JS, il suffit de supprimer le tiret et de remplacer la lettre qui suit par son équivalent en majuscule.

Prenons quelques exemples :

propriéténom en CSSnom en JS
couleur de fondbackground-colorbackgroundColor
bordure (méga propriété)borderborder
hauteur de ligneline-heightlineHeight
marge externe gauchemargin-leftmarginLeft

On appelle cette technique de nommage : "camelCase".

Modifier les éléments HTML

Vous savez donc désormais récupérer les paramètres d'un élément du DOM : contenu d'un élément, valeurs des attributs, valeurs des propriétés CSS.
Mais pour obtenir des pages dynamiques (dont l'apparence évolue suite à des événements déclenchés par l'utilisateur) il faut savoir modifier les valeurs de ces paramètres ...

Modifier le contenu d'un élément

Thème : Un clic sur la drapeau tricolore et le texte est en français ; un clic sur l'Union Jack, alors le texte est en anglais.

CSS & HTML

Les éléments H2, FIGCAPTION et P sont vides de tout contenu !
C'est l'exécution du script qui va remplir ces balises.

Le script

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
	
	// les fonctions
	function fran()
	{ 		// page en français
		titre.innerText = "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.innerText = "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 

En cliquant sur le drapeau tricolore on appelle la fonction fran qui remplit chaque élément avec un texte français.
En cliquant sur l'Union Jack on appelle la fonction angl qui remplit chaque élément avec un texte anglais.

Le rendu de ce code dans un Iframe

Modifier les valeurs des attributs

Thème : sur beaucoup de sites et dans le cadre du formulaire de connexion, les caractères que vous saisissez dans un champ "mot de passe" peuvent être affichés en cliquant sur une icône (un oeil).
Il suffit qu'un script transforme le type de ce champ : de type "password" à type "text".

Le code HTML

Une image représentant un oeil (facile à trouver sur la toile) est affichée à côté du champ de type "password".
Une légende est associée à l'image : 'afficher le mot de passe'.
Si clic sur cette image : appel d'une fonction.

Le script

Il est d'un simplicité déroutante:

function f_oeil()
{
	if (f.motdepasse.getAttribute('type')=='password') 
		{f.motdepasse.setAttribute('type','text'); }
	else
		{f.motdepasse.setAttribute('type','password'); }
}

Si le champ "motdepasse" est de type "password" alors il devient de type "text" sinon c'est l'inverse.

Le script peut être encore plus simple en utilisant la notation simplifiée pour récupérer/modifier la valeur d'un atribut.

function f_oeil()
{
	if (f.motdepasse.type=='password') 
		{f.motdepasse.type = 'text' }
	else
		{f.motdepasse.type ='password' }
}

Le rendu du code :

Supprimer un attribut

Avec la méthode removeAttribute() il est possible de supprimer un ou plusieurs attributs d'un élément.
La syntaxe : élément.removeAttribute('attribut').

Thématique : une page commprend différentes images ; un clic sur une image provoque son effacement via la suppression de l'attribut SRC.

Le code correspondant

Il ne s'agit pas en fait de la suppression d'un élément mais de la suppression de l'attribut SRC ; seul attribut obligatoire pour une balise IMG.

Le rendu du code

Modifier les propriétés de style

Ci-dessous un document HTML les images ont été chargées mais sont masquées (display : none).
En cliquant sur un bouton le visiteur les affiche ; en cliquant sur un autre bouton le visiteur les masque de nouveau.
Ci-dessous ce document :

Le code CSS & HTML

Via le sélecteur img de la feuille de style les images sont masquées (display : none).
Donc pour les démasquer il faut que la valeur de la propriété display passe à "inline" (ou "block").
Pour les masquer de nouveau la propriété display doit repasser à "none".

Le script - extrait

Je ne vous communique qu'une fonction anonyme sur les deux ; à vous de trouver le code de la seconde.

var images_page = document.querySelectorAll('img'); 
	
	// fonction anonyme pour afficher les images 
	document.querySelector('button').onclick = function()
	{
		for(image of images_page)	{ image.style.display = 'inline' ; 	}
	} 
	
	// fonction anonyme pour masquer les images 
	...

La structure for ... of ... est très pratique pour parcourir un objet Array. Or la méthode document.querySelectorAll() retourne un tableau !

Ajouter, supprimer des classes

Pour modifier rapidement le style d'éléments, le plus simple est de jouer sur les classes : ajout / suppression / basculement d'une classe.
Basculement ("toogle" en anglais) : supprimer la classe si elle est appliquée OU ajouter si elle n'est pas appliquée.

Ci-dessous un document HTML dans un Iframe

Après avoir cliqué sur les deux boutons de commande, affichez la console du navigateur puis onglet "éléments".
Vous lisez alors que trois classes sont désormais appliquées à chaque élément IMG.

Le code CSS & HTML de ce document

La classe "base" est déjà attribuée aux images. C'est elle qui redimensionne et positionne les images.
Deux autres classes sont définies dans la feuille de style : .cadre & .ombre mais ne sont pas encore appliquées par défaut.

L'objet classList

Une version récente de JavaScript a ajouté l'objet classList qui comprend plusieurs méthodes pour manipuler les classes.

Toggle : basculer.

Le script correspondant

document.querySelector('button').onclick = function()
{
	var collection = document.querySelectorAll('img'); 
	for (var i in collection)
	{	
		collection[i].classList.toggle('cadre'); 
	}
} 
document.querySelectorAll('button')[1].onclick = function()
{
	var collection = document.querySelectorAll('img'); 
	for (var i in collection)
	{	
		collection[i].classList.toggle('ombre'); 
	}
}

La méthode toggle() doit être priviligiée.

Ajouter / supprimer des éléments

Sachez que l'on peut encore aller plus loin dans la modification du DOM initial. On peut en effet ajouter de nouveaux éléments voire supprimer des éléments existants.

Créer puis insérer un nouvel élément

Il faut d'abord créer un élément puis insérer le nouvel à un endroit précis de la page.
Plutôt que de créer un nouvel élément, il est possible de cloner un élément existant.

Théme : insertion dans une page d'un lien vers une feuille de style externe puis d'une image et enfin suppression des boutons d'insertion.

Le code correspondant

La page est très moche car il n'y a aucune mise en forme.

Le script

	var page = document.querySelector('body');
	
	document.querySelector('button').onclick = function() 
	{
		var lien =document.createElement('link');
		lien.href ="../style.css"; 
		lien.rel ="stylesheet";
		document.querySelector('head').appendChild(lien); 
		document.querySelector('p').textContent =
			"Page désormais plus jolie !!!" ; 
		page.removeChild(this); 
		// suppression bouton
	}
	document.querySelectorAll('button')[1].onclick = function() 
	{
		var image =document.createElement('img');
		image.src ="../images/bikini.jpg";
		image.alt ="jolie fille en bikini";
		image.style.width ="100px";
		document.querySelector('section').appendChild(image); 
		page.removeChild(this); 
		//suppression bouton
	}

Si clic sur le premier bouton il y a alors insertion d'une balise LINK dans la partie HEAD. Cet élément charge une feuille de style.
Si clic sur deuxième bouton il y a alors insertion dans la boite SECTION d'une belle 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 parent.appendChild(enfant)

Après avoir été cliqué chaque bouton est supprimé via la méthode parent.removeChild(enfant)

Le rendu du code :

Cloner un élément existant puis insérer le clone

Plutôt que de créer un nouvel élément de toute pièce on peut cloner un élément existant.

Le code

Il faut utiliser la méthode cloneNode() puis appendChild()

Le rendu

A chaque fois que vous cliquez sur le bouton de commande il y a duplication de la boite DIV.

Affichez l'onglet "éléments" de la console du navigateur pour observer la modification du DOM.

Suppression d'éléments

Nous avons vu que l'on pouvait supprimer des éléments du DOM avec la méthode parent. removeChild(enfant) Mais il existe aussi la méthode élément.remove().
Je la présente via deux exemples.

Exemple 1 : suppression de l'image courante

Le code de la page

Notez l'emploi de "this" dans l'attribut onclick pour désigner l'élément courant.

Exemple 2 : suppression de toutes les images

Le bouton de commande n'est pas supprimé ...

Le code de la page

Complétez le script pour que le bouton de commande "supprimer les images" soit aussi supprimé.