Introduction au Document Object Model
Introduction au Document Object Model
Plan de la séance
● DOM
○ Représentation d'arborescence
○ Interfaces du DOM
● Objets globaux du navigateur
● Manipulation du DOM
○ Collections statiques et vivantes
○ Propriétés dataset
● Événements
○ Gestionnaires dʼévénements
○ Événements de la souris et du clavier
○ Propagation des événements
● Boucle dʼévénements
○ Séparation entre JS et code natif
○ Exemple récapitulatif
Génie informatique et génie logiciel – LOG2440 A2024 2 2
Semaine 5 – DOM
● LʼAPI du DOM décrit des interfaces qui sont implémentées par chaque engin de rendu.
○ Événements (Event) : les éléments sont en mode "écoute" pour des événements sʼils
implémentent lʼinterface EventTarget
■ Ex: HTMLButtonElement dont la chaîne dʼhéritage remonte jusquʼà EventTarget
■ Ex: XMLHttpRequest (communication réseau) qui nʼest pas un noeud du DOM
DOM
● Les nœuds qui composent le DOM implémentent le plus souvent une des interfaces suivantes:
○ Element: il sʼagit dʼun élément du document.
■ Lʼinterface HTMLElement en hérite et définit les éléments HTML
○ Text: il sʼagit du contenu texte dʼun Element et ne peut pas avoir dʼautres nœuds comme enfants :
■ <p> texte en <strong> gras </strong> ici </p>
contient 3 noeuds text : "texte en", "gras" et "ici"
et 2 nœuds element : <p> et <strong>
vs <p> texte en gras ici </p>
qui a 1 seul nœud text et 1 noeud element
● Les nœuds forment un arbre dont la racine est lʼobjet Document . Son parent est null
● Les noeuds peuvent avoir 0, 1 ou plusieurs enfants en fonction de leur type
Génie informatique et génie logiciel – LOG2440 A2024 4 4
Semaine 5 – DOM
Exemple dʼarbre
<html>
<head>
<title>Un document </title>
</head>
<body>
<h1>Titre</h1>
Allo
<p>Bla <strong>bla</strong> bla</p>
</body>
</html>
<html>
<html>
<html>
<HTMLHeadElement>
tagName: head
<html>
<HTMLHeadElement>
tagName: head
<HTMLTitleElement>
tagName: title
<Text>
nodeValue : Un document
<html>
<HTMLHeadElement> <HTMLBodyElement>
tagName: head tagName: body
<HTMLTitleElement>
tagName: title
<Text>
nodeValue : Un document
<html>
<HTMLHeadElement> <HTMLBodyElement>
tagName: head tagName: body
<Text>
nodeValue : bla
11
Génie informatique et génie logiciel – LOG2440 A2024 11
Semaine 5 – DOM
Node
Node
Propriétés
Méthodes
Element
childNodes
Document
Attr
appendChild() CharacterData
firstChild
cloneNode() lastChild
contains() nextSibling
hasChildNodes() nodeName
Text Comment HTMLElement HTMLDocument
insertBefore() nodeType
removeChild() parentNode
replaceChild() parentElement
normalize() previousSibling
etc. HTMLHeadElementª HTMLBodyElementª HTMLTitleElementª
textContent
HTMLInputElementª ETC.
Note: les propriétés en rouge sont accessibles seulement en lecture. Ces listes ne sont pas exhaustives.
Génie informatique et génie logiciel – LOG2440 A2024
13
13
Semaine 5 – DOM
previousElementSibling
<HTMLHeadElement> <HTMLBodyElement>
tagName: head tagName: body
parentNode
nextSibling
<Text>
nodeValue : bla
nextSibling
14
Génie informatique et génie logiciel – LOG2440 A2024 14
Semaine 5 – DOM
Element
Node
Méthodes
Propriétés
(hérités d’EventTarget)
attributesDocument
addEventListener()
Attr CharacterData Element
childElementCount
removeEventListener()
children
firstElementChild
getAttribute()
Text Comment HTMLElement id HTMLDocument
getElementsByClassName()
innerHTML
getElementsByTagName()
lastElementChild
querySelector()
nextElementSibling
querySelectorAll()
previousElementSibling
removeAttribute() HTMLHeadElementª HTMLBodyElementª HTMLTitleElementª HTMLInputElementª ETC.
tagName
setAttribute()
Note: les propriétés en rouge sont accessibles seulement en lecture. Ces listes ne sont pas exhaustives.
Génie informatique et génie logiciel – LOG2440 A2024
15
15
Semaine 5 – DOM
<HTMLHeadElement> <HTMLBodyElement>
tagName: head tagName: body
previousElementSibling
<Text>
nodeValue : bla
16
Génie informatique et génie logiciel – LOG2440 A2024 16
Semaine 5 – DOM
Le danger dʼinnerHTML
<html>
<head>
Le code sera exécuté dès qu’on passe par-dessus l’élément.
<title>Un document </title>
</head> On peut insérer du code arbitraire et potentiellement dangereux.
Ex: application de messagerie sans vérification du contenu
<body>
récupéré du serveur et affiché à l’écran.
<h1>Titre</h1>
Allo Ceci est une attaque de type XSS (Cross Site Scripting)
<p>Bla <strong>bla</strong> bla</p>
</body>
<script>
const element = [Link];
[Link] = `<p onmouseenter="[Link]('[Link] par
innerHTML</p>`;
</script>
</html>
lʼobjet Document
Node
Méthodes
Objet window
● Objet qui représente la fenêtre qui contient le document DOM.
○ Nʼest PAS un élément du DOM en soi.
Objet window
● Propriétés globales:
○ console (retourne une référence vers lʼobjet Console)
○ document (référence vers le Document de la page)
○ navigator (référence vers les fonctionnalités du navigateur : peuvent varier beaucoup)
○ etc.
● Méthodes globales:
○ alert() : évitez à lʼutiliser puisque ceci bloque lʼexécution de la page au complet
○ open() / close() : le script doit avoir été la source de lʼouverture dʼune fenêtre pour la fermer
○ onload : indique que la page a été chargée et peut être manipulée
○ etc.
Exemple simple
<html>
<script>
[Link] = function() {
const heading = [Link] ("h1");
const heading_text = [Link] ("Grand titre" );
[Link] (heading_text );
[Link] (heading);
}
</script>
</html>
Exemple complexe
function createElementWithClasses(elementType, classes) {
const element = [Link](elementType); Les éléments sont créés et ajoutés
[Link](...classes); comme enfants avec la même structure
return element; que le HTML statique
}
const parent = createElementWithClasses("div", ["message", source]);
[Link]("id", `message-${[Link] + 1}`);
Conteneurs dʼobjets
● Les collections dʼéléments HTMLCollection et NodeList sont retournées par certaines fonctions
○ Ex : getElementsByTagName() retourne une HTMLCollection
○ Attention : HTMLCollection nʼest pas un objet Array dans le sens dʼun tableau JS.
● Conteneurs « vivants » (live): les changements dans le DOM seront reflétés dans la collection.
● NodeList retourné par querySelectorAll() nʼest pas « vivant », mais plutôt statique (static)
○ La collection nʼest pas affectée par des modifications du DOM après sa création
Propriété dataset
● Contient les attributs ayant la forme data-*, dans la balise de lʼélément
● Pour chacune des occurrences, on génère une propriété dont le nom
correspond à tout ce qui vient après « data- », sans les tirets, et où tout
caractère qui succède à un tiret est mis en majuscule
○ Ex: data-date-of-birth donne dateOfBirth en JavaScript
○ Les majuscules qui suivent un tiret dans le nom de lʼattribut sont ignorées
● Utile si on veut ajouter de lʼinformation directement dans une balise HTML
○ Exemple : serveur fournit une page HTML et laisse le client décider quoi
faire avec lʼinformation dans le dataset
Événement (Event)
● Possède un nom unique : click, change, load, mouseover, etc.
● Possède une cible (target) : lʼélément sur lequel il a été déclenché.
○ La cible peut différente de lʼendroit où il est géré
● On lui associe une fonction qui sera appelée lorsque celui-ci sera déclenché
○ Appelée "gestionnaire dʼévénement" (event handler ou event listener)
● Trois manières dʼassocier un gestionnaire dʼévénement à un élément:
○ Écrire le code directement dans la balise HTML (déconseillé)
○ Associer une fonction à un attribut de lʼélément (onX), X étant lʼévénement
○ Utiliser la méthode addEventListener(event, handler) :
■ permet dʼajouter plusieurs gestionnaires à un événement (recommandé)
Événement
● Le gestionnaire peut recevoir en paramètre un objet Event qui fournit de
lʼinformation sur lʼévénement
○ Ex : la cible, la position de la souris, la touche appuyée, etc.
● Certains événements ont une action par défaut qui leur est associée:
○ Ex : Clic sur un hyperlien <a href ="...">: se déplacer à lʼURL indiquée
○ Cette action peut être annulée, mais pas dans tous les cas
■ Ex : on ne peut pas empêcher le déroulement (scroll) dʼune page
Génie informatique et génie logiciel – LOG2440 A2024
35
35
Semaine 5 – DOM
Interface Event
● Propriétés principales:
○ target : lʼélément sur lequel lʼévénement a été déclenché
○ cancelable : si on peut annuler le comportement par défaut
○ type : le nom de lʼévénement
● Méthodes:
○ preventDefault(): annule le comportement par défaut de lʼévénement
○ stopPropagation(): interrompt la propagation de lʼévénement
● Certains événements ont une propriété relatedTarget, qui identifie un élément secondaire
○ Ex : pour mouseover, ce sera lʼélément dʼoù provient la souris
● Interfaces plus spécialisées pour des événements spécifiques avec plus dʼattributs
○ Ex : [Link] qui indique la touche appuyée
Génie informatique et génie logiciel – LOG2440 A2024
36
36
Semaine 5 – DOM
nom ("click", "mouseover", etc.) Fonction exécutée chaque fois que lʼévénement est
déclenché
[Link](événement,gestionnaire,options)
time
}; Questions :
addMessage(message, 'self'); - Pourquoi la condition du "if" ?
- Que se passe si
[Link] = ""; [Link] est vide ?
}
});
● Si le gestionnaire est défini avec une expression de fonction dans addEventListener(), il nʼest
pas possible de lʼenlever puisquʼon nʼa pas de référence à passer à removeEventListener()
● Si on clone un noeud avec cloneNode(), les gestionnaires dʼévénements ne sont pas copiés
○ Pratique si on veut enlever des gestionnaires créés avec des expressions de fonction
Suppression : exemple
const copyToInput = function (event) {
Bloquer le comportement par défaut
[Link](); "contextmenu" = bouton droit
[Link]().
then(text => [Link] = text);
};
[Link]("copy-checkbox").addEventListener('change', (event) => {
const messageInput = [Link]("message-input");
if ([Link]) {
[Link]('contextmenu', copyToInput);
} Référence vers la même fonction
else {
[Link]('contextmenu', copyToInput);
}
});
Génie informatique et génie logiciel – LOG2440 A2024
40
40
Semaine 5 – DOM
Propagation dʼévénements
Suppression de la propagation
● Possible dʼarrêter la propagation dʼun événement dans la hiérarchie
○ stopPropagation() bloque la propagation au-delà de lʼélément ou elle est invoquée. Ceci arrête un
seul événement et ne bloque pas le comportement par défaut.
■ Note: lʼévénement doit être annulable (cancelable), sinon rien ne se passe ex: scroll
<table id="tableau">
<th>Exemple de bubbling</th>
<tr id="ligne1"><td id="cell1">CELLULE #1</td></tr>
<tr id="ligne2"><td id="cell2">CELLULE #2</td></tr>
</table> Génie informatique et génie logiciel – LOG2440 A2024
43
43
Semaine 5 – DOM
Propagation : exemple
La propagation vers le parent est arrêtée
par [Link]()
Événements de formulaires
● submit et reset
○ input est lancé chaque fois que le contenu dʼun input est modifié
Autres événements
● Événements associés aux balises <audio> et <video>
○ canplay, playing, pause, etc.
○ storage
La boucle dʼévénements
DOM
ajax (XMLHttpRequest)
func2()
setTimeout
func1()
main()
Event loop
callback
onClick onClick onLoad
queue
[Link]
Génie informatique et génie logiciel – LOG2440 A2024
47
47
Semaine 5 – DOM
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
} Code JS
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
Exécution de la fonction
function gestionnaire () {
setTimeout (show_alert , 3000);
clicking();
} stack
WebAPIs
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
} Code JS
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue callback
}
function clicking(){
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
gestionnaire()
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
gestionnaire()
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
gestionnaire()
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
gestionnaire()
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
gestionnaire()
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert("The clicker was clicked" );
}
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
show_alert()
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
alert()
alert("The clicker was clicked" );
} show_alert()
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
[Link]('click', () => gestionnaire()); queue
}
function clicking(){
gestionnaire()
alert("The clicker was clicked" );
} callback
[Link] = function () {
Event loop
show_alert();
const bouton = [Link]('#clicker'); callback
show_alert()
[Link]('click', () => gestionnaire()); queue
}
Task
queue Task
Comment ça fonctionne?
Ils existent aussi des micro-tâches (Micro-Task) stack
WebAPIs
- Toujours exécutées après le code synchrone (stack vide)
- La file de micro-tâches est exécutée jusquʼà quʼelle soit vide
- Ceci peut causer une boucle infinie bloquante
Render
queue Render
Task
queue Task
Event Loop