Comment puis-je supprimer tous les éléments enfants d'un nœud DOM en JavaScript?
Disons que j'ai le code HTML (laid) suivant:
<p id="foo">
<span>hello</span>
<div>world</div>
</p>
Et je prends le noeud que je veux comme ça:
var myNode = document.getElementById("foo");
Comment puis-je supprimer les enfants de foo
afin qu'il ne reste que <p id="foo"></p>
?
Puis-je faire juste:
myNode.childNodes = new Array();
ou devrais-je utiliser une combinaison de removeElement
?
J'aimerais que la réponse soit tout droit sorti de DOM; points supplémentaires si vous fournissez également une réponse dans jQuery avec la réponse DOM uniquement.
Option 1 (beaucoup plus lente, voir les commentaires ci-dessous):
var myNode = document.getElementById("foo");
myNode.innerHTML = '';
Option 2 (beaucoup plus rapide):
var myNode = document.getElementById("foo");
while (myNode.firstChild) {
myNode.removeChild(myNode.firstChild);
}
La réponse actuellement acceptée est fausse à propos du ralentissement de innerHTML (du moins dans IE et Chrome), comme indiqué correctement dans m93a.
Chrome et FF sont considérablement plus rapides avec cette méthode (qui détruira les données jquery attachées):
var cNode = node.cloneNode(false);
node.parentNode.replaceChild(cNode ,node);
dans une seconde lointaine pour FF et Chrome, et le plus rapide dans IE:
node.innerHTML = '';
InnerHTML ne détruira pas vos gestionnaires d'événements ni ne cassera les références jQuery, il est également recommandé comme solution ici: https://developer.mozilla.org/en-US/docs/Web/ API/Element.innerHTML
La méthode de manipulation DOM la plus rapide (toujours plus lente que les deux précédentes) est la suppression de la plage, mais les plages ne sont pas prises en charge avant IE9.
var range = document.createRange();
range.selectNodeContents(node);
range.deleteContents();
Les autres méthodes mentionnées semblent comparables, mais beaucoup plus lentes que innerHTML, à l'exception de la requête aberrante jquery (1.1.1 et 3.1.1), qui est considérablement plus lente que toute autre chose:
$(node).empty();
Preuve ici:
http://jsperf.com/innerhtml-vs-removechild/167http://jsperf.com/innerhtml-vs-removechild/300 https://jsperf.com/remove-all-child-elements-of-a-domode-node-in-javascript (Nouvelle URL pour le redémarrage de jsperf car l'édition de l'ancienne URL isn ' t de travail)
La "boucle par test" de Jsperf est souvent comprise comme une "per-itération", et seule la première itération a des nœuds à supprimer, ainsi les résultats n'ont pas de sens. Au moment de la publication, des tests dans ce fil avaient été configurés de manière incorrecte.
var myNode = document.getElementById("foo");
var fc = myNode.firstChild;
while( fc ) {
myNode.removeChild( fc );
fc = myNode.firstChild;
}
S'il existe un risque que vos descendants soient affectés par jQuery, vous devez utiliser une méthode permettant de nettoyer les données jQuery.
$('#foo').empty();
La méthode jQuery .empty()
garantira que toutes les données associées à jQuery avec les éléments à supprimer seront nettoyées.
Si vous utilisez simplement les méthodes DOM
pour supprimer les enfants, ces données seront conservées.
Si vous utilisez jQuery:
$('#foo').empty();
Si vous ne le faites pas:
var foo = document.getElementById('foo');
while (foo.firstChild) foo.removeChild(foo.firstChild);
remove
!const parent = document.getElementById("foo");
while (parent.firstChild) {
parent.firstChild.remove();
}
Il s'agit d'une méthode plus récente pour écrire la suppression de nœud dans ES5. Il est Vanilla JS et lit beaucoup plus agréable que les versions précédentes.
La plupart des utilisateurs devraient avoir des navigateurs modernes ou vous pouvez transpiler si nécessaire.
Support par navigateur - 91% Avr 2018
Le plus rapide...
var removeChilds = function (node) {
var last;
while (last = node.lastChild) node.removeChild(last);
};
Merci à Andrey Lushnikov pour son lien vers jsperf.com (site sympa!).
EDIT: pour que ce soit clair, il n'y a pas de différence de performances dans Chrome entre firstChild et lastChild. La première réponse montre une bonne solution pour la performance.
Si vous voulez seulement avoir le noeud sans ses enfants, vous pouvez aussi en faire une copie comme ceci:
var dupNode = document.getElementById("foo").cloneNode(false);
Cela dépend de ce que vous essayez d’atteindre.
Voici une autre approche:
function removeAllChildren(theParent){
// Create the Range object
var rangeObj = new Range();
// Select all of theParent's children
rangeObj.selectNodeContents(theParent);
// Delete everything that is selected
rangeObj.deleteContents();
}
element.textContent = '';
C'est comme innerText, sauf standard. C'est un peu plus lent que removeChild()
, mais il est plus facile à utiliser et ne fera pas une grande différence de performances si vous n'avez pas trop de choses à supprimer.
En réponse à DanMan, Maarten et Matt. Cloner un nœud, définir le texte est en effet un moyen viable dans mes résultats.
// @param {node} node
// @return {node} empty node
function removeAllChildrenFromNode (node) {
var Shell;
// do not copy the contents
Shell = node.cloneNode(false);
if (node.parentNode) {
node.parentNode.replaceChild(Shell, node);
}
return Shell;
}
// use as such
var myNode = document.getElementById('foo');
myNode = removeAllChildrenFromNode( myNode );
De plus, cela fonctionne pour les noeuds ne figurant pas dans le dom qui retournent la valeur null lorsqu'ils tentent d'accéder au parentNode. En outre, si vous devez être en sécurité, un nœud est vide avant d'ajouter du contenu, cela est très utile. Considérez le cas d'utilisation ci-dessous.
// @param {node} node
// @param {string|html} content
// @return {node} node with content only
function refreshContent (node, content) {
var Shell;
// do not copy the contents
Shell = node.cloneNode(false);
// use innerHTML or you preffered method
// depending on what you need
Shell.innerHTML( content );
if (node.parentNode) {
node.parentNode.replaceChild(Shell, node);
}
return Shell;
}
// use as such
var myNode = document.getElementById('foo');
myNode = refreshContent( myNode );
Je trouve cette méthode très utile pour remplacer une chaîne dans un élément. Si vous ne savez pas exactement ce que le nœud va contenir, au lieu de vous demander comment nettoyer le désordre, recommencez à zéro.
Il y a plusieurs options pour y parvenir:
Le plus rapide ():
while (node.lastChild) {
node.removeChild(node.lastChild);
}
Alternatives (plus lent):
while (node.firstChild) {
node.removeChild(node.firstChild);
}
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
j'ai vu des gens faire:
while (el.firstNode) {
el.removeChild(el.firstNode);
}
alors quelqu'un a dit en utilisant el.lastNode
est plus rapide
cependant, je pense que c'est le plus rapide:
var children = el.childNodes;
for (var i=children.length - 1; i>-1; i--) {
el.removeNode(children[i]);
}
qu'est-ce que tu penses?
ps: ce sujet a été une bouée de sauvetage pour moi. mon addon firefox a été rejeté parce que j'ai utilisé innerHTML. C'est une habitude depuis longtemps. alors je foudn cela. et j'ai effectivement remarqué une différence de vitesse. à la charge, le innerhtml a mis du temps à se mettre à jour, mais passe à addElement son instant!
var empty_element = function (element) {
var node = element;
while (element.hasChildNodes()) { // selected elem has children
if (node.hasChildNodes()) { // current node has children
node = node.lastChild; // set current node to child
}
else { // last child found
console.log(node.nodeName);
node = node.parentNode; // set node to parent
node.removeChild(node.lastChild); // remove last node
}
}
}
Cela supprimera tous les nœuds de l'élément.
Manière la plus simple de supprimer les nœuds enfants d'un nœud via Javascript
var myNode = document.getElementById("foo");
while(myNode.hasChildNodes())
{
myNode.removeChild(myNode.lastChild);
}
innerText est le gagnant! http://jsperf.com/innerhtml-vs-removechild/133 . Lors de tous les tests précédents, les domaines internes du nœud parent ont été supprimés à la première itération, puis innerHTML ou removeChild ont été appliqués à div vide.
Utiliser une boucle de distance me semble le plus naturel:
for (var child of node.childNodes) {
child.remove();
}
Selon mes mesures dans Chrome et Firefox, il est environ 1,3x plus lent. Dans des circonstances normales, cela n'aura peut-être pas d'importance.
Voici ce que je fais habituellement:
HTMLElement.prototype.empty = function() {
while (this.firstChild) {
this.removeChild(this.firstChild);
}
}
Et voila, plus tard, vous pouvez vider n'importe quel élément dom avec:
anyDom.empty()
Généralement, JavaScript utilise des tableaux pour référencer des listes de nœuds DOM. Donc, cela fonctionnera bien si vous avez un intérêt à le faire via le tableau HTMLElements. A noter également, car j'utilise une référence à un tableau au lieu de JavaScript, cela devrait fonctionner dans n'importe quel navigateur, y compris IE.
while(nodeArray.length !== 0) {
nodeArray[0].parentNode.removeChild(nodeArray[0]);
}
Je viens de voir quelqu'un mentionner cette question dans une autre et j'ai pensé ajouter une méthode que je n'ai pas encore vue:
function clear(el) {
el.parentNode.replaceChild(el.cloneNode(false), el);
}
var myNode = document.getElementById("foo");
clear(myNode);
La fonction clear prend l'élément et utilise le nœud parent pour se remplacer par une copie sans ses enfants. Peu de gain de performance si l'élément est rare, mais lorsque l'élément a un ensemble de nœuds, les gains de performance sont réalisés.
Pourquoi ne suivons-nous pas la méthode la plus simple ici, "remove" en boucle à l'intérieur.
const foo = document.querySelector(".foo");
while (foo.firstChild) {
foo.firstChild.remove();
}