Développement Web

Introduction au Document Object Model (DOM)

Romuald THION

Semestre pair 2022 UNC

L’API DOM

Qu’est ce que le Document Object Model (DOM) ?

  • le (DOM) n’est pas JavaScript, c’est une API (Application Programming Interface)
  • cette interface standard permet d’interagir programmatiquement avec les contenus en mémoire dans le navigateur
    • exemples : documents HTML, XML, SVG, MathML etc.
  • tous les navigateurs proposent une interface JavaScript avec une implémentation conforme à cette API, mais elle est aussi disponible pour d’autres langages
    • par exemple, xml.dom dans la bibliothèque standard de Python
  • sans le DOM, JavaScript dans le navigateur ne pourrait presque rien faire, car très limité en I/O
    • JS s’exécute dans un bac à sable pour des raisons de sécurité

L’arbre HTML via le DOM

Le DOM propose une interface pour naviguer et éditer les documents via leurs représentations en mémoire, le DOM tree.

Le document HTML
L’arbre DOM associé

Source javascript.info

Dynamique de l’arbre DOM

  • l’arbre DOM est accessible depuis l’objet automatiquement instancié document
  • les éléments HTML deviennent des nodes (noeuds) de l’arbre
  • tout est représenté dans l’arbre, même les commentaires et les scripts qui ne sont pas visibles à l’utilisateur
  • l’arbre DOM est live : les modifications effectuées en JS sont visibles immédiatement et réciproquement

Les principaux types de données

Le système de classes du DOM est riche avec de nombreuses interfaces et abstractions, voir Difference between Node object and Element object?

Interface Description
EventTarget La classe la plus abstraite, avec la gestion événementielle partagée par tous
Document le type de la racine de l’abre DOM, l’objet document
Interface Description
Node un noeud abstrait de l’arbre, soit un Element soit du texte
Element Une interface abstraite pour les éléments, hérite de Node, commun à HTMLElement et SVGElement
Interface Description
HTMLElement Un élément HTML (improprement balises), est spécialisé par les éléments concrets comme HTMLAnchorElement
NodeList Un tableau de noeuds, pour stocket les fils par exemple. Similaire mais non identique à Array de la lib standard JS
et bien d’autres
Principales classes des noeuds du DOM

Source javascript.info

Hiérarchie d’interfaces/classes du DOM des éléments anchors <a> dans le DOM

Source MDN

Quelques méthodes incontournables

Sélection des noeuds du DOM

  • document.querySelector(selector) sélectionne le premier élément du sélecteur
  • document.querySelectorAll(selector) sélection tous les éléments du sélecteur
  • document.getElementById(id) similaire, mais par identifiant uniquement (plus efficace)

Les sélecteurs sont des string dans la syntaxe des sélecteurs CSS. Voir https://javascript.info/searching-elements-dom

const $anchors = document.querySelectorAll("li > a");
  • document.createElement(tag, options) créer un objet représentant un élément HTML
  • parentNode.appendChild(node) ajoute un dernier fils à un élément
  • element.innerHTML pour lire ou écrire un contenu en HTML directement
  • element.setAttribute() et element.getAttribute() pour modifier les attributs des éléments

Chargement et exécution du JavaScript dans la page

Méthodes pour intégrer du JS dans un page HTML

  • directement en ligne dans le HTML (à bannir, sauf pour les petites démonstrations)
  • directement dans l’élément HTML <script> (à éviter)
  • via l’attribut src de l’élément <script>, attributs possibles async et defer :
  • aucun attribut : le script est immédiatement exécuté après la lecture
    • attention le contenu de la page n’est peut-être pas encore disponible
  • attribut defer : le script est exécuté après l’analyse de toute la page et exécuté juste avant l’événement DOMContentLoaded.
    • si plusieurs scripts, ils sont exécutés dans l’ordre
    • c’est souvent ce qu’on veut
  • attribut async : le script sera téléchargé puis exécuté quand le navigateur pourra
    • il n’y a aucun de contrôle sur l’ordre d’exécution
    • ne pas utiliser si on manipule le DOM

Le mode strict

Ajouter "use strict" en tout début de programme impose d’interpréter le fichier en mode strict, impacte :

  • la déclaration des variables : doit être explicite
  • meilleur contrôle des modifications d’objets
  • modification de eval et arguments
  • this reste undefined s’il n’est pas spécifié das une fonction (et ne pointe pas vers windows)
  • note : les modules sont implicitement en mode strict

Pratique obligatoire, voir MDN et javascript.info.

Exercice sur le DOM

Voir l’exemple de demo.html et les fichiers demo_1.js et demo_2.js.

  • identifier où sont chargés les 3 scripts.
  • expliquer l’ordre des affichages dans la console.
  • pourquoi le NodeList du deuxième affichage est-il vide ?
  • quelle est l’erreur sur $anchors et pourquoi ? La corriger.
  • ajouter dynamiquement (en JS) un boutton Test.
  • avec console.log() afficher le nombre de <li> de la page
  • ajouter dynamiquement (en JS) à document.body un nouveau item avec un lien
  • avec console.log(), vérifier que le nombre de <li> de la page a augmenté
  • faire en sorte que le bouton Test soit positionné à côté du bouton Démo existant avec Element.insertAdjacentElement()

Les événements

Les événements DOM sont déclenchés pour notifier au code des « changements intéressants » qui peuvent affecter l’exécution du code. Ces changements peuvent résulter d’interactions avec l’utilisateur, […], de changements dans l’état de l’environnement […], et d’autres causes. Chaque événement est représenté par un objet implémentant l’interface Event […].

MDN Event reference

Fonctionnement

De nombreux éléments DOM peuvent être paramétrés afin d’accepter (« d’écouter ») ces évènements et d’exécuter du code en réaction afin de les traiter (« gérer »).

MDN Event Event handling (overview)

  • un objet DOM (ou tout objet ayant l’interface EventTarget) peut écouter (listen) certains événements
  • on attache un gestionnaire appelé handler ou listener (on ne fera pas la nuance) à cet événement

On peut attacher un handler de deux façons

  • element.addEventListener("click", listener, options)
    • méthode recommandée
  • un attribut spécial onevent comme element.onclick = listener
    • méthode historique
    • correcte, plus facile si un seul handler
    • moins flexible, limitée à un seul handler

Important : le handler est une fonction :

  • element.onclick = handlerFunct() n’est exécuté qu’une seule fois, ceci n’a pas de sens et provoquera une erreur si handlerFunct() renvoie un objet qui ne peut pas être appellé
  • element.onclick = handlerFunct l’appel handlerFunct() sera exécuté à chaque occurrence de l’événement "click"

Deux variantes

const $btn = document.querySelector("button");

function greet(...args) {
  console.log("greet:", args);
}
$btn.onclick = greet;
const $btn = document.querySelector("button");

function greet(...args) {
  console.log("greet:", args);
}
$btn.addEventListener("click", greet);

this dans les handlers

When a function is used as an event handler, its this is set to the element on which the listener is placed

MDN

const $btn = document.querySelector("button");

function greet(event) {
  // affiche le texte du premier boutton de la page
  // et deux attributs de l'évenement "click"
  console.log(this.innerText, event.type, event.timeStamp);
}
$btn.addEventListener("click", greet);

Question de réflexion

Est-il utile de renvoyer une valeur de retour dans un handler ? Comment peut-on y accéder ?

const $btn = document.querySelector("button");

function greet(...args) {
  return "Bonjour";
}
$btn.addEventListener("click", greet);
// comment retrouver la valeur "Bonjour" ?

Exercice sur les événements

Convention JS préfixer les identifiants des éléments avec $ et donner le nom camelCase que l’attribut id HTML ou le sélecteur utilisé (si possible).

A faire :

  • Ajouter un handler au bouton demo-btn pour qu’il ajoute une nouvelle ligne de texte dans l’élément code avec le nombre de fois où on a cliqué sur le boutons.
  • Ajouter un handler au bouton Test ajouté dynamiquement qui aura pour effet de vider l’élément code et de RàZ le compteur précédent.
  • Faire en sorte que quand on clique sur le bouton “Calculer”, un pop-up s’affiche avec le carré du nombre saisi dans le champs