Nous souhaitons rendre ce projet open source disponible pour les gens du monde entier.
Aidez-nous à traduire le contenu de ce tutoriel dans votre langue!
Modification du document
La modification DOM est la clé pour créer des pages “live”.
Ici, nous verrons comment créer de nouveaux éléments “à la volée” et modifier le contenu de la page existante.
Exemple : afficher un message
Démontrons en utilisant un exemple. Nous allons ajouter un message sur la page qui est plus joli que alert.
Voici à quoi cela ressemblera :
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<div class="alert">
<strong>Hi there!</strong> You've read an important message.
</div>
C’était un exemple HTML. Créons maintenant la même div avec JavaScript (en supposant que les styles sont déjà dans le HTML ou un fichier CSS externe).
Création d’un élément
Pour créer des nœuds DOM, il existe deux méthodes :
document.createElement(tag)-
Crée un nouveau noeud élément avec la balise donnée :
let div = document.createElement('div'); document.createTextNode(text)-
Crée un nouveau nœud texte avec le texte donné :
let textNode = document.createTextNode('Here I am');
La plupart du temps, nous devons créer des nœuds d’élément, tels que le div pour le message.
Création du message
La création du message div prend 3 étapes :
// 1. Create <div> element
let div = document.createElement('div');
// 2. Set its class to "alert"
div.className = "alert";
// 3. Fill it with the content
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
Nous avons créé l’élément. Mais pour le moment, ce n’est que dans une variable nommée div, pas encore dans la page. Nous ne pouvons donc pas le voir.
Méthodes d’insertion
Pour faire apparaître la div, nous devons l’insérer quelque part dans document. Par exemple, dans l’élément <body>, référencé par document.body.
Il existe une méthode spéciale append pour cela : document.body.append(div).
Voici le code complet :
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<script>
let div = document.createElement('div');
div.className = "alert";
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
document.body.append(div);
</script>
Ici, nous avons appelé append sur document.body, mais nous pouvons appeler la méthode append sur n’importe quel autre élément, pour y mettre un autre élément. Par exemple, nous pouvons ajouter quelque chose à <div> en appelant div.append(anotherElement).
Voici plus de méthodes d’insertion, elles spécifient différents endroits où insérer :
node.append(...nodes or strings)– ajouter des nœuds ou des chaînes de caractères à la fin denode,node.prepend(...nodes or strings)– insérer des nœuds ou des chaînes de caractères au début denode,node.before(...nodes or strings)–- insérer des nœuds ou des chaînes de caractères avantnode,node.after(...nodes or strings)–- insérer des nœuds ou des chaînes de caractères aprèsnode,node.replaceWith(...nodes or strings)–- remplacenodeavec les nœuds ou chaînes de caractères donnés.
Les arguments de ces méthodes sont une liste arbitraire de nœuds DOM à insérer ou des chaînes de texte (qui deviennent automatiquement des nœuds de texte).
Voyons-les en action.
Voici un exemple d’utilisation de ces méthodes pour ajouter des éléments à une liste et le texte avant/après :
<ol id="ol">
<li>0</li>
<li>1</li>
<li>2</li>
</ol>
<script>
ol.before('before'); // insère la chaîne de caractères "before" avant <ol>
ol.after('after'); // insère la chaîne de caractères "after" après <ol>
let liFirst = document.createElement('li');
liFirst.innerHTML = 'prepend';
ol.prepend(liFirst); // insère liFirst au début de <ol>
let liLast = document.createElement('li');
liLast.innerHTML = 'append';
ol.append(liLast); // insère liLast à la fin de <ol>
</script>
Voici une image visuelle de ce que font les méthodes :
La liste finale sera donc :
before
<ol id="ol">
<li>prepend</li>
<li>0</li>
<li>1</li>
<li>2</li>
<li>append</li>
</ol>
after
Comme indiqué, ces méthodes peuvent insérer plusieurs nœuds et morceaux de texte en un seul appel.
Par exemple, ici une chaîne de caractères et un élément sont insérés :
Remarque: le texte est inséré “en tant que texte”, pas “en tant que HTML”, avec un échappement approprié des caractères tels que <, >.
Le HTML final est donc :
En d’autres termes, les chaînes de caractères sont insérées de manière sûre, comme le fait elem.textContent.
Ainsi, ces méthodes ne peuvent être utilisées que pour insérer des nœuds DOM ou des morceaux de texte.
Mais que se passe-t-il si nous voulons insérer du HTML “en tant que html”, avec toutes les balises et les trucs qui fonctionnent, comme elem.innerHTML le fait ?
insertAdjacentHTML/Text/Element
Pour cela, nous pouvons utiliser une autre méthode assez polyvalente : elem.insertAdjacentHTML(where, html).
Le premier paramètre est un mot de code, spécifiant où insérer par rapport à elem. Doit être l’un des suivants :
"beforebegin"– insèrehtmlimmédiatement avantelem,"afterbegin"– insèrehtmldanselem, au début,"beforeend"– insèrehtmldanselem, à la fin,"afterend"– insèrehtmlimmédiatement aprèselem.
Le second paramètre est une chaîne HTML insérée “au format HTML”.
Par exemple :
…Conduirait à :
Voilà comment nous pouvons ajouter du code HTML arbitraire à la page.
Voici l’image des variantes d’insertion :
Nous pouvons facilement remarquer des similitudes entre cette image et l’image précédente. Les points d’insertion sont en fait les mêmes, mais cette méthode insère du HTML.
La méthode a deux sœurs :
elem.insertAdjacentText(where, text)– la même syntaxe, mais une chaîne de caractèrestextest inséréeen tant que texteau lieu de HTML,elem.insertAdjacentElement(where, elem)– la même syntaxe, mais insère un élément.
Elles existent principalement pour rendre la syntaxe “uniforme”. En pratique, seule insertAdjacentHTML est utilisée la plupart du temps. Parce que pour les éléments et le texte, nous avons des méthodes append/prepend/before/after – elles sont plus courtes à écrire et peuvent insérer des nœuds/morceaux de texte.
Voici donc une variante alternative pour afficher un message :
Suppression de noeuds
Pour supprimer un nœud, il existe une méthode node.remove().
Faisons disparaître notre message après une seconde :
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<script>
let div = document.createElement('div');
div.className = "alert";
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
document.body.append(div);
setTimeout(() => div.remove(), 1000);
</script>
Veuillez noter : si nous voulons déplacer un élément vers un autre endroit – il n’est pas nécessaire de le supprimer de l’ancien.
Toutes les méthodes d’insertion suppriment automatiquement le nœud de l’ancien emplacement.
Par exemple, permutons les éléments :
Clonage de Noeuds : cloneNode
Comment insérer un autre message similaire ?
Nous pourrions créer une fonction et y mettre le code. Mais l’alternative serait de cloner la div existant et de modifier le texte à l’intérieur (si nécessaire).
Parfois, lorsque nous avons un gros élément, cela peut être plus rapide et plus simple.
- L’appel
elem.cloneNode(true)crée un clone “profond” de l’élément – avec tous les attributs et sous-éléments. Si nous appelonselem.cloneNode(false), alors le clone est fait sans éléments enfants.
Un exemple de copie du message :
<style>
.alert {
padding: 15px;
border: 1px solid #d6e9c6;
border-radius: 4px;
color: #3c763d;
background-color: #dff0d8;
}
</style>
<div class="alert" id="div">
<strong>Hi there!</strong> You've read an important message.
</div>
<script>
let div2 = div.cloneNode(true); // clone the message
div2.querySelector('strong').innerHTML = 'Bye there!'; // change le clone
div.after(div2); // affiche le clone après le div existant
</script>
DocumentFragment
DocumentFragment est un nœud DOM spécial qui sert de wrapper pour passer autour des listes de nœuds.
Nous pouvons y ajouter d’autres nœuds, mais lorsque nous l’insérons quelque part, son contenu est inséré à la place.
Par exemple, getListContent ci-dessous génère un fragment avec des éléments <li>, qui sont ensuite insérés dans <ul> :
Veuillez noter qu’à la dernière ligne (*) nous ajoutons DocumentFragment, mais il “s’adapte”, donc la structure résultante sera :
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
DocumentFragment est rarement utilisé explicitement. Pourquoi ajouter à un type spécial de nœud, si nous pouvons renvoyer un tableau de nœuds à la place ? Exemple réécrit :
Nous mentionnons DocumentFragment principalement parce qu’il y a quelques concepts dessus, comme l’élément template, que nous couvrirons beaucoup plus tard.
Méthodes d’insertion/suppression à l’ancienne
Il existe également des méthodes de manipulation du DOM “à l’ancienne”, qui existent pour des raisons historiques.
Ces méthodes viennent d’une époque très ancienne. De nos jours, il n’y a aucune raison de les utiliser, depuis qu’il existe des méthodes modernes, telles que append, prepend, before, after, remove, replaceWith, qui sont plus flexibles.
La seule raison pour laquelle nous listons ces méthodes ici est que vous pouvez les trouver dans de nombreux anciens scripts :
parentElem.appendChild(node)-
Appends
nodeas the last child ofparentElem.The following example adds a new
<li>to the end of<ol>: parentElem.insertBefore(node, nextSibling)-
Insère
nodeavantnextSiblingdansparentElem.Le code suivant insère un nouvel élément de liste avant le second
<li>:Pour insérer
newLicomme premier élément, nous pouvons le faire comme ceci :list.insertBefore(newLi, list.firstChild); parentElem.replaceChild(node, oldChild)-
Remplace
oldChildavecnodechez les enfants deparentElem. parentElem.removeChild(node)-
Supprime
nodedeparentElem(en supposant quenodeest son enfant).L’exemple suivant supprime d’abord
<li>de<ol>:
Toutes ces méthodes renvoient le nœud inséré/supprimé. En d’autres termes, parentElem.appendChild(node) renvoie node. Mais généralement, la valeur retournée n’est pas utilisée, nous exécutons simplement la méthode.
Un mot sur “document.write”
Il existe une autre méthode très ancienne pour ajouter quelque chose à une page Web : document.write.
La syntaxe :
L’appel à document.write(html) écrit le html dans la page “ici et maintenant”. La chaîne de caractères html peut être générée dynamiquement, donc c’est un peu flexible. Nous pouvons utiliser JavaScript pour créer une page Web à part entière et l’écrire.
La méthode vient de l’époque où il n’y avait pas de DOM, pas de standards … Des temps vraiment anciens. Il vit toujours, car il existe des scripts qui l’utilisent.
Dans les scripts modernes, nous le voyons rarement, en raison de la limitation importante suivante :
L’appel à document.write ne fonctionne que pendant le chargement de la page.
Si nous l’appelons ensuite, le contenu du document existant est effacé.
Par exemple :
C’est donc un peu inutilisable au stade “post chargement”, contrairement aux autres méthodes DOM que nous avons couvertes ci-dessus.
Voilà l’inconvénient.
Il y a aussi un avantage. Techniquement, lorsque document.write est appelé pendant que le navigateur lit (“analyse”) le HTML entrant, et qu’il écrit quelque chose, le navigateur le consomme comme s’il était initialement là, dans le texte HTML.
Cela fonctionne donc très rapidement, car il n’y a aucune modification du DOM impliquée. Il écrit directement dans le texte de la page, tandis que le DOM n’est pas encore construit.
Donc, si nous devons ajouter beaucoup de texte en HTML de manière dynamique, et que nous sommes en phase de chargement de page, et que la vitesse compte, cela peut aider. Mais dans la pratique, ces exigences se rencontrent rarement. Et généralement, nous pouvons voir cette méthode dans les scripts simplement parce qu’ils sont anciens.
Résumé
-
Méthodes pour créer de nouveaux nœuds :
document.createElement(tag)– crée un élément avec la balise donnée,document.createTextNode(value)– crée un nœud texte (rarement utilisé),elem.cloneNode(deep)– clone l’élément, sideep==truetous les descendants viennent avec.
-
Insertion et suppression :
node.append(...nodes or strings)– insère dansnode, à la fin,node.prepend(...nodes or strings)– insère dansnode, au début,node.before(...nodes or strings)–- insère juste avantnode,node.after(...nodes or strings)–- insère juste aprèsnode,node.replaceWith(...nodes or strings)–- remplacenode.node.remove()–- supprime lenode.
Les chaînes de caractères texte sont insérées “sous forme de texte”.
-
Il existe également des méthodes “old school” :
parent.appendChild(node)parent.insertBefore(node, nextSibling)parent.removeChild(node)parent.replaceChild(newElem, node)
Toutes ces méthodes retournent le
node. -
Étant donné un peu de HTML dans
html,elem.insertAdjacentHTML(where, html)l’insère en fonction de la valeur dewhere:"beforebegin"– insèrehtmljuste avantelem,"afterbegin"– insèrehtmldanselem, au début,"beforeend"– insèrehtmldanselem, à la fin,"afterend"– insèrehtmljuste aprèselem.
Il existe également des méthodes similaires,
elem.insertAdjacentTextetelem.insertAdjacentElement, qui insèrent des chaînes de caractères texte et des éléments, mais ils sont rarement utilisés. -
Pour ajouter du HTML à la page avant la fin du chargement :
document.write(html)
Une fois la page chargée, un tel appel efface le document. Surtout vu dans les anciens scripts.
Exercices
Nous avons un élément DOM vide elem et une chaîne de caractères text.
Lesquelles de ces 3 commandes feront exactement la même chose ?
elem.append(document.createTextNode(text))elem.innerHTML = textelem.textContent = text
Réponse : 1 et 3.
Les deux commandes ont pour résultat d’ajouter le texte “en tant que texte” dans elem.
Voici un exemple :
Créez une fonction clear(elem) qui supprime tout de l’élément.
Voyons d’abord comment ne pas le faire :
function clear(elem) {
for (let i=0; i < elem.childNodes.length; i++) {
elem.childNodes[i].remove();
}
}
Cela ne fonctionnera pas, car l’appel à remove() décale la collection elem.childNodes, donc les éléments commencent à partir de l’index 0 à chaque fois. Mais i augmente et certains éléments seront ignorés.
La boucle for..of fait de même.
La bonne variante pourrait être :
function clear(elem) {
while (elem.firstChild) {
elem.firstChild.remove();
}
}
Et il existe également un moyen plus simple de faire de même :
function clear(elem) {
elem.innerHTML = '';
}
Dans l’exemple ci-dessous, l’appel table.remove() supprime le tableau du document.
mais si vous l’exécutez, vous pouvez voir que le texte "aaa" est toujours visible.
Pourquoi cela se produit-il ?
Le code HTML de cette tâche est incorrect. Voilà la raison de la chose étrange.
Le navigateur doit le réparer automatiquement. Mais il peut ne pas y avoir de texte à l’intérieur de la <table> : selon la spécification, seules les balises spécifiques à la table sont autorisées. Le navigateur ajoute donc "aaa" avant la <table>.
Maintenant, il est évident que lorsque nous retirons la table, la chaîne de caractères reste.
La question peut être facilement répondue en explorant le DOM à l’aide des outils du navigateur. Vous verrez "aaa" avant la <table>.
Le standard HTML spécifie en détail comment traiter un mauvais HTML, et un tel comportement du navigateur est correct.
Écrivez une interface pour créer une liste à partir des entrées utilisateur.
Pour chaque élément de la liste :
- Interrogez un utilisateur sur son contenu en utilisant
prompt. - Créez le
<li>avec et ajoutez-le à<ul>. - Continuez jusqu’à ce que l’utilisateur annule l’entrée (en appuyant sur la touche Esc ou une entrée vide).
Tous les éléments doivent être créés dynamiquement.
Si un utilisateur tape des balises HTML, elles doivent être traitées comme un texte.
Veuillez noter l’utilisation de textContent pour attribuer le contenu <li>.
Écrivez une fonction createTree qui crée une liste imbriquée ul/li à partir de l’objet imbriqué.
Par exemple :
let data = {
"Fish": {
"trout": {},
"salmon": {}
},
"Tree": {
"Huge": {
"sequoia": {},
"oak": {}
},
"Flowering": {
"apple tree": {},
"magnolia": {}
}
}
};
La syntaxe :
let container = document.getElementById('container');
createTree(container, data); // crée l'arbre dans le conteneur
Le résultat (arbre) devrait ressembler à ceci :
Choisissez l’une des deux façons de résoudre cette tâche :
- Créez le code HTML de l’arborescence, puis attribuez-le à
container.innerHTML. - Créez des nœuds d’arbre et ajoutez-les avec les méthodes DOM.
Ce serait génial si vous pouviez faire les deux.
P.S. L’arbre ne doit pas avoir d’éléments “supplémentaires” comme des <ul></ul> vides pour les feuilles (de l’arbre).
La façon la plus simple de parcourir l’objet est d’utiliser la récursivité.
Il y a un arbre organisé comme un ul/li imbriqué.
Écrivez le code qui ajoute à chaque <li> le nombre de ses descendants. Sautez les feuilles (nœuds sans enfants).
Le resultat :
Pour ajouter du texte à chaque <li>, nous pouvons modifier le nœud texte data.
Écrivez une fonction createCalendar(elem, year, month).
L’appel doit créer un calendrier pour l’année/le mois donné et le mettre dans elem.
Le calendrier doit être un tableau, où une semaine est un <tr> et un jour est un <td>. Le dessus du tableau doit être un <th> avec les noms des jours de la semaine : le premier jour doit être le lundi, et ainsi de suite jusqu’au dimanche.
Par exemple, createCalendar(cal, 2012, 9) devrait générer dans l’élément cal le calendrier suivant :
P.S. Pour cette tâche, il suffit de générer le calendrier, il ne doit pas encore être cliquable.
Nous allons créer le tableau sous forme de chaîne de caractères : "<table>...</table>", puis l’affecter à innerHTML.
L’algorithme :
- Créer l’en-tête du tableau avec les noms
<th>et les jours de la semaine. - Créez l’objet de date
d = new Date(year, month-1). C’est le premier jour demonth(en tenant compte du fait que les mois en JavaScript commencent à0, pas à1). - Les premières cellules jusqu’au premier jour du mois
d.getDay()peuvent être vides. Remplissons-les avec<td></td>. - Augmentez le jour en
d:d.setDate(d.getDate()+1). Sid.getMonth()n’est pas encore le mois suivant, alors ajoutez la nouvelle cellule<td>au calendrier. Si c’est un dimanche, ajoutez une nouvelle ligne“</tr><tr>”. - Si le mois est terminé, mais que la ligne du tableau n’est pas encore pleine, ajoutez-y un
<td>vide pour le rendre carré.
Créez une horloge colorée comme ici :
Utilisez HTML/CSS pour le style, JavaScript ne met à jour que le temps dans les éléments.
Tout d’abord, créons notre HTML/CSS.
Chaque composante du temps aurait fière allure dans son propre <span> :
<div id="clock">
<span class="hour">hh</span>:<span class="min">mm</span>:<span class="sec">ss</span>
</div>
Nous aurons également besoin de CSS pour les colorer.
La fonction update rafraîchira l’horloge, qui sera appelée par setInterval toutes les secondes :
function update() {
let clock = document.getElementById('clock');
let date = new Date(); // (*)
let hours = date.getHours();
if (hours < 10) hours = '0' + hours;
clock.children[0].innerHTML = hours;
let minutes = date.getMinutes();
if (minutes < 10) minutes = '0' + minutes;
clock.children[1].innerHTML = minutes;
let seconds = date.getSeconds();
if (seconds < 10) seconds = '0' + seconds;
clock.children[2].innerHTML = seconds;
}
Dans la ligne (*) nous vérifions à chaque fois la date actuelle. Les appels à setInterval ne sont pas fiables : ils peuvent survenir avec des retards.
Les fonctions de gestion d’horloge :
let timerId;
function clockStart() { // exécute l'horloge
if (!timerId) { // défini un nouvel intervalle uniquement si l'horloge ne fonctionne pas
timerId = setInterval(update, 1000);
}
update(); // (*)
}
function clockStop() {
clearInterval(timerId);
timerId = null; // (**)
}
Veuillez noter que l’appel à update() est non seulement planifié dans clockStart(), mais s’exécute immédiatement dans la ligne (*). Sinon, le visiteur devra attendre la première exécution de setInterval. Et l’horloge serait vide jusque-là.
Il est également important de définir un nouvel intervalle dans clockStart() uniquement lorsque l’horloge ne fonctionne pas. Sinon, cliquer plusieurs fois sur le bouton de démarrage définirait plusieurs intervalles simultanés. Pire encore, nous ne garderions que le timerID du dernier intervalle, perdant ainsi les références à tous les autres. Alors nous ne pourrions plus jamais arrêter le chronomètre! Notez que nous devons effacer le timerID lorsque l’horloge est arrêtée dans la ligne (**), afin qu’elle puisse être redémarrée en exécutant clockStart().
Écrivez le code pour insérer <li>2</li><li>3</li> entre deux <li> ici :
<ul id="ul">
<li id="one">1</li>
<li id="two">4</li>
</ul>
Lorsque nous devons insérer un morceau de HTML quelque part, insertAdjacentHTML est le meilleur choix.
La solution :
one.insertAdjacentHTML('afterend', '<li>2</li><li>3</li>');
Il y a un tableau :
Il peut y avoir plus de lignes.
Écrivez le code pour le trier par la colonne "name".
La solution est courte, mais peut sembler un peu délicate, alors ici je la présente avec de nombreux commentaires :
let sortedRows = Array.from(table.tBodies[0].rows) // 1
.sort((rowA, rowB) => rowA.cells[0].innerHTML.localeCompare(rowB.cells[0].innerHTML));
table.tBodies[0].append(...sortedRows); // (3)
L’algorithme pas à pas :
- Obtenez tous les
<tr>de<tbody>. - Triez-les ensuite en les comparant au contenu du premier
<td>(le champ du nom). - Insérez maintenant les nœuds dans le bon ordre par
.append(...sortedRows).
Nous n’avons pas à supprimer les éléments de ligne, il suffit de les “réinsérer”, ils quittent automatiquement l’ancien emplacement.
P.S. Dans notre cas, il y a un <tbody> explicite dans le tableau, mais même si le tableau HTML n’a pas de <tbody>, la structure DOM l’a toujours.
- © 2007—2026 Ilya Kantor
- à propos du projet
- nous contacter
Commentaires
<code>, pour plusieurs lignes – enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen…)