Le DOM

Sommaire

Introduction

La principale fonction de Javascript est d'interagir avec le DOM : le Document Object Model.

Le document HTML est représenté en Javascript par l'objet document. Cet objet dispose de plusieurs propriétés et fonctions dont vous trouverez la liste ici.

Essayez par exemple d'afficher les propriétés title et URL de votre document.

index.html
<!doctype html>
<html lang="fr">
<head>
    <title>Cours Javascript</title>
</head>

<body>
    <h1>Ma page HTML</h1>

    <script src="js/script.js"></script>
</body>
</html>
js/script.js
console.log(document.title);  // Cours Javascript
console.log(document.URL);    // http://...

Les sélecteurs

À partir de l'objet document, nous allons pouvoir récupérer n'importe quel élément HTML présent dans la page en utilisant des sélecteurs.

getElementById()

La manière la plus rapide d'accéder à un élément HTML est de lui attribuer un ID puisque celui-ci est supposé être unique. Dans l'exemple ci-dessous, nous avons ajouté à la page un élément div avec l'ID content

<!doctype html>
<html lang="fr">
<head>
  <title>Cours Javascript</title>
</head>

<body>
  <h1>Ma page HTML</h1>

  <div id="content">
    <p>Mon contenu</p>
  </div>

  <script src="js/script.js"></script>
</body>
</html>

Pour récupérer cet élément en Javascript, on exécutera la fonction getElementById() sur l'objet document en précisant l'ID de l'élément en paramètre.

var element = document.getElementById('content');

Si l'élément existe, Javascript renverra un objet de type Element, autrement la valeur renvoyée sera null

Les objets Element possèdent, entre autres, les propriétés suivantes :

  • innerHTML : renvoie le contenu HTML de l'élément
  • id : renvoie l'ID de l'élément
  • classList : renvoie la ou les classe(s) CSS de l'élément
  • tagName : renvoie le nom de la balise de l'élément

Pour afficher le contenu de notre élément dans la console, on pourra donc utiliser innerHTML

var element = document.getElementById('content');

console.log(element.innerHTML);

On peut aussi affecter une valeur à la propriété innerHTML pour modifier le contenu de notre élément.

var element = document.getElementById('content');

element.innerHTML = "Mon nouveau contenu";

getElementsByClassName()

Lorsque vous souhaitez sélectionner plusieurs éléments d'une même classe, vous pouvez utiliser la fonction getElementsByClassName() (attention au s à Elements) qui prend en paramètre un nom de classe et retourne un objet de type HTMLCollection qui fonctionne comme un tableau.

<!doctype html>
<html lang="fr">
<head>
  <title>Cours Javascript</title>
</head>

<body>
  <h1>Ma page HTML</h1>

  <section class="section">
    <p>Ma première section</p>
  </section>

  <section class="section">
    <p>Ma deuxième section</p>
  </section>

  <script src="js/script.js"></script>
</body>
</html>
var elements = document.getElementsByClassName('section');

console.log(elements);

Étant donné que la valeur retournée est un tableau, il faudra donc effectuer une boucle pour accéder à chaque élément.

var elements = document.getElementsByClassName('section');

for (var i = 0; i < elements.length; i++) {
  elements[i].innerHTML = "Mon nouveau contenu";
}

querySelector()

La fonction querySelector() permet de récupérer un élément en utilisant un sélecteur. Les sélecteurs pris en compte par cette fonction sont les mêmes que les sélecteurs CSS.

Pour récupérer un élément par son ID, on peut donc tout à fait utiliser querySelector() à la place de getElementById() à condition de ne pas oublier le symbole #. Les deux instructions ci-dessous sont alors équivalentes :

document.getElementById('content');
document.querySelector('#content');

Grâce à querySelector(), vous pouvez utiliser des sélecteurs complexes pour cibler des éléments précis dans le DOM.

L'instruction ci-dessous remplacera le premier paragraphe de l'élément qui a la classe section par "Hello!"

document.querySelector('.section p:first-child').innerHTML = 'Hello!';

Attention : la recherche de l'élément s'arrêtera à la première occurrence trouvée car querySelector() ne peut retourner qu'un seul élément.

querySelectorAll()

La fonction querySelectorAll() est l'équivalent de querySelector() pour récupérer plusieurs éléments.

À la différence de getElementsByClassName(), querySelectorAll() retourne un objet de type NodeList.

console.log(document.getElementsByClassName('section'));  // retourne un objet HTMLCollection
console.log(document.querySelectorAll('.section'));       // retourne un objet NodeList

Comme l'objet HTMLCollection, NodeList se comporte comme un tableau. Pour effectuer des opérations sur tous les éléments retournés par le sélecteur, on pourra donc effectuer une boucle classique.

let paragraphs = document.querySelectorAll('.section p');

for (var i = 0; i < paragraphs.length; i++) {
  paragraphs[i].innerHTML = "Hello!";
}

Mais contrairement à HTMLCollection, NodeList dispose nativement d'une méthode forEach() qui permet d'itérer sur chaque élément.

// Syntaxe classique
document.querySelectorAll('.section p').forEach(function (element) {
  element.innerHTML = 'Hello!';
});

// Syntaxe fléchée
document.querySelectorAll('.section p').forEach(element => {
  element.innerHTML = 'Hello!';
});

La méthode forEach() appelle pour chaque itération une fonction que l'on appelle fonction de rappel (ou callback). Cette dernière prend en paramètre l'élément en cours de traitement.

Lorsque vous utilisez une fonction de callback, vous pouvez l'écrire de façon classique avec le mot-clé function ou utiliser la version fléchée (voir fonctions fléchées)

La méthode forEach() est relativement récente et n'est pas supportée par Internet Explorer. Il ne faut donc l'utiliser que si le support des navigateurs très anciens n'est pas requis.

Les événements

Lorsqu'on veut rendre un élément du DOM interactif, on doit lui ajouter un EventListener (littéralement un "écouteur d'événements") pour associer une fonction à un événement. Il existe différents types d'événements qui peuvent différer selon le type d'élément associé. Par exemple, on pourra associer un événement click ou keypress à n'importe quel élément HTML, un événement resize à la fenêtre ou bien play et pause à une vidéo ou un fichier audio.

Pour attacher un événement à un élément, on utilisera la fonction addEventListener qui prend deux paramètres : le nom de l'événement à écouter et la fonction à exécuter lorsque l'événement est actif.

click

<button>Cliquez ici</button>
document.querySelector('button').addEventListener('click', (ev) => {
    alert('Hello!');
});

Le code javascript ci-dessus affiche une pop-up lors du clic sur l'élément <button>.

La fonction de rappel (callback) prend en paramètre un objet de type Event qui contient des informations potentiellement utiles sur l'événement. Dans l'exemple ci-dessus, l'événement correspond à une variable que nous avons appelé ev.

Si l'on affiche la valeur de cette variable dans la console, on peut voir la liste des attributs disponibles tels que :

  • pageX, pageY : position de la souris par rapport au document HTML
  • clientX, clientY : position de la souris par rapport à la fenêtre
  • offsetX, offsetY : position de la souris par rapport à l'élément qui a reçu l'événement
  • target: élément à l'origine de l'événement

Ces attributs diffèrent en fonction du type d'événement. Dans le cas de click, l'événement est de type PointerEvent et ses attributs renseignent sur la position du curseur.

scroll

On peut attacher l'événement scroll à n'importe quel élément qui dispose de la propriété overflow: scroll ou tout simplement à la fenêtre du navigateur. Cet événement ne renvoie pas d'attributs particuliers mais on peut tout simplement récupérer la propriété scrollY de la fenêtre à chaque scroll pour savoir de combien de pixels l'utilisateur a fait défiler la page.

window.addEventListener('scroll', (ev) => {
    console.log(window.scrollY);
});

mouseenter, mouseleave, mousemove

Les événements mouseenter et mouseleave sont exécutés respectivement lorsque la souris entre sur un élément et lorsqu'elle le quitte. L'événement mousemove est exécuté chaque fois que la souris bouge au-dessus d'un élément.

<section style="height: 400px; background-color: pink;">
    <p>Passez votre souris ici.</p>
</section>
document.querySelector('section').addEventListener('mouseenter', (ev) => {
    console.log("La souris est dans la section");
});

document.querySelector('section').addEventListener('mouseleave', (ev) => {
    console.log("La souris n'est plus dans la section");
});

keypress, keyup, keydown

Les événements keypress, keyup et keydown correspondent à l'appui sur une touche du clavier. Ils sont naturellement utilisés sur les champs de saisie.

  • keypress est exécuté lorsqu'une touche est appuyée puis relâchée
  • keydown est exécuté lorsqu'une touche est appuyée
  • keyup est exécuté lorsqu'une touche est relâchée
<input type="text" placeholder="Saisissez votre nom" />
document.querySelector('input').addEventListener('keypress', (ev) => {
  console.log("Vous avez tapé la touche " + ev.key);
});

L'événement correspondant est de type KeyboardEvent et possède des informations sur la touche pressée.

  • key : caractère saisi
  • keyCode : code ASCII du caractère saisi

submit

Un élément <form> envoie un événement submit de type SubmitEvent lorsqu'il est validé.

<form id="contact-form">
    <div class="control">
        <label for="name">Votre nom</label>
        <input id="name" type="text" placeholder="Votre nom" />
    </div>

    <div class="control">
        <label for="message">Votre message</label>
        <textarea id="message" placeholder="Écrivez-nous ici"></textarea>
    </div>

    <button>Valider</button>
</form>
document.querySelector('#contact-form').addEventListener('submit', (ev) => {
    console.log("Merci pour votre message !");
});

Le code ci-dessus ne va afficher le message de la console qu'une fraction de seconde car la soumission d'un formulaire a pour effet par défaut de rediriger vers une nouvelle page. Pour éviter cela, on peut utiliser la méthode preventDefault() sur l'événement pour indiquer au navigateur de ne pas appliquer le comportement par défaut lors de cette action.

document.querySelector('#contact-form').addEventListener('submit', (ev) => {
    // Ne pas exécuter l'action par défaut lors de la soumission du formulaire
    ev.preventDefault();

    console.log("Merci pour votre message !");
});

On peut alors par exemple vérifier si les champs sont correctement remplis puis dire au navigateur de finalement soumettre le formulaire si tout est bon. Pour cela, il suffira d'exécuter la méthode submit() sur le formulaire.

document.querySelector('#contact-form').addEventListener('submit', (ev) => {
    // Ne pas exécuter l'action par défaut lors de la soumission du formulaire
    ev.preventDefault();

    if (document.querySelector('#name').value.length === 0) {
        alert('Merci de renseigner votre nom.');
    } else {
        ev.target.submit();
    }
});

Manipuler le CSS avec Javascript

Manipuler les styles

Chaque élément HTML dispose d'un attribut style qui renvoie un objet de type CSSStyleDeclaration. Cet objet contient toutes les propriétés CSS de l'élément auxquelles on peut affecter directement des valeurs.

let button = document.querySelector('.button');

// Affiche l'intégralité des propriétés CSS de l'élément
console.log(button.style);

// Affiche uniquement la valeur de la propriété background-color
console.log(button.style.backgroundColor);

// Attribue une valeur à la propriété background-color
button.style.backgroundColor = 'lightblue';

Les noms des propriétés CSS de l'objet CSSStyleDeclaration sont écrites en camelCase. Par exemple, l'équivalent de border-top-left-radius est donc borderTopLeftRadius.

Manipuler les classes

Chaque élément HTML dispose d'un attribut classList qui renvoie un objet de type DOMTokenList. Cet objet fonctionne comme un tableau et possède les méthodes suivantes :

  • add(className [, className]) : ajouter une ou plusieurs classe(s) à la liste
  • remove(className [, className]) : supprime une ou plusieurs classe(s) de la liste
  • toggle(className) : ajoute ou supprime la classe en fonction de son existence dans la liste
  • contains(className) : vérifie si la classe existe dans la liste
  • replace(old, new) : remplace une classe par une autre
let button = document.querySelector('.button');

// Ajoute la classe is-large à l'élément
button.classList.add('is-large');

// Ajoute les classes is-large et is-primary à l'élément
button.classList.add('is-large', 'is-primary');

// Supprime la classe is-large de l'élément
button.classList.remove('is-large');

// Ajoute la classe is-large si elle n'existe pas
// ou supprime la classe si elle existe
button.classList.toggle('is-large');

// Vérifie si la classe is-large est présente
if (button.classList.contains('is-large')) {
    // Remplace la classe is-large par is-small
    button.classList.replace('is-large', 'is-small');
}

Créer un player vidéo HTML

Javascript peut être utilisé pour manipuler des fichers audio et vidéo. Dans cet exemple, nous créons dans en HTML une interface de lecture avec :

  • Un élément <video>
  • Un bouton de lecture/pause
  • Un bouton pour activer/désactiver le son
  • Une tête de lecture

Un élément HTML <video> est représenté en Javascript par un objet de type HTMLVideoElement qui hérite de la classe HTMLMediaElement, qui dispose de fonctions et de propriétés permettant d'interagir avec le média.

See the Pen Untitled by Marc Bellêtre (@marcbelletre) on CodePen.