Eliminar todos los elementos secundarios de un nodo DOM en JavaScript

Resuelto DigitalZebra asked hace 14 años • 39 respuestas

¿Cómo haría para eliminar todos los elementos secundarios de un nodo DOM en JavaScript?

Digamos que tengo el siguiente HTML (feo):

<p id="foo">
    <span>hello</span>
    <div>world</div>
</p>

Y tomo el nodo que quiero así:

var myNode = document.getElementById("foo");

¿Cómo podría quitar a los hijos de foopara que solo <p id="foo"></p>quede?

¿Podría simplemente hacer:

myNode.childNodes = new Array();

¿O debería usar alguna combinación de removeElement?

Me gustaría que la respuesta fuera directamente DOM; aunque puntos extra si también proporciona una respuesta en jQuery junto con la respuesta solo DOM.

DigitalZebra avatar Oct 18 '10 03:10 DigitalZebra
Aceptado

Opción 1 A: Compensación innerHTML.

  • Este enfoque es simple, pero puede no ser adecuado para aplicaciones de alto rendimiento porque invoca el analizador HTML del navegador (aunque los navegadores pueden optimizarlo para el caso en que el valor sea una cadena vacía).

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  myNode.innerHTML = '';
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via innerHTML</button>
Expandir fragmento

Opción 1 B: CompensacióntextContent

  • Como arriba, pero use .textContent. Según MDN, esto será más rápido ya que innerHTMLlos navegadores no invocarán sus analizadores HTML y, en su lugar, reemplazarán inmediatamente todos los elementos secundarios del elemento con un solo #textnodo.

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  myNode.textContent = '';
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via textContent</button>
Expandir fragmento

Opción 2 A: bucle para eliminar cada lastChild:

  • Se utilizó una edición anterior de esta respuesta firstChild, pero se actualizó para usarla lastChildcomo en informática, en general , es significativamente más rápido eliminar el último elemento de una colección que eliminar el primer elemento (dependiendo de cómo se implemente la colección). ).
  • El bucle continúa verificando firstChild en caso de quefirstChild sea más rápido verificarlo lastChild(por ejemplo, si la UA implementa la lista de elementos como una lista enlazada dirigida).

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  while (myNode.firstChild) {
    myNode.removeChild(myNode.lastChild);
  }
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via lastChild-loop</button>
Expandir fragmento

Opción 2 B: bucle para eliminar cada lastElementChild:

  • Este enfoque preserva todos los nodos Element(es decir, #textnodos y <!-- comments -->) hijos del padre (pero no sus descendientes), y esto puede ser deseable en su aplicación (por ejemplo, algunos sistemas de plantillas que utilizan comentarios HTML en línea para almacenar instrucciones de plantilla).
  • Este enfoque no se utilizó hasta los últimos años, ya que Internet Explorer solo agregó soporte para lastElementChildIE9.

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  while (myNode.lastElementChild) {
    myNode.removeChild(myNode.lastElementChild);
  }
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <!-- This comment won't be removed -->
  <span>Hello <!-- This comment WILL be removed --></span>
  <!-- But this one won't. -->
</div>
<button id='doFoo'>Remove via lastElementChild-loop</button>
Expandir fragmento

Bono: Element.clearChildrenparche de mono:

  • Podemos agregar una nueva propiedad de método al Elementprototipo en JavaScript para simplificar su invocación a solo el.clearChildren()(dónde elestá cualquier objeto de elemento HTML).
  • (Estrictamente hablando, este es un parche de mono, no un polyfill, ya que no es una característica DOM estándar o una característica faltante. Tenga en cuenta que el parche de mono se desaconseja con razón en muchas situaciones).

if( typeof Element.prototype.clearChildren === 'undefined' ) {
    Object.defineProperty(Element.prototype, 'clearChildren', {
      configurable: true,
      enumerable: false,
      value: function() {
        while(this.firstChild) this.removeChild(this.lastChild);
      }
    });
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello <!-- This comment WILL be removed --></span>
</div>
<button onclick="this.previousElementSibling.clearChildren()">Remove via monkey-patch</button>
Expandir fragmento

Gabriel McAdams avatar Oct 17 '2010 20:10 Gabriel McAdams

¡En 2022+, use la replaceChildren()API!

Ahora se puede reemplazar a todos los niños con la replaceChildrenAPI (compatible con varios navegadores) :

container.replaceChildren(...arrayOfNewChildren);

Esto hará ambas cosas:

  • eliminar todos los niños existentes, y
  • agregue todos los nuevos hijos dados, en una sola operación.

También puedes usar esta misma API para simplemente eliminar elementos secundarios existentes, sin reemplazarlos:

container.replaceChildren();

Esto es totalmente compatible con Chrome/Edge 86+, Firefox 78+ y Safari 14+. Es un comportamiento completamente especificado . Es probable que esto sea más rápido que cualquier otro método propuesto aquí, ya que la eliminación de los hijos antiguos y la adición de nuevos hijos se realiza sin necesidad de innerHTML, y en un solo paso en lugar de en varios.

Mason Freed avatar Dec 22 '2020 18:12 Mason Freed

Utilice Javascript moderno, con remove!

const parent = document.getElementById("foo")
while (parent.firstChild) {
    parent.firstChild.remove()
}

Esta es una forma más nueva de escribir la eliminación de nodos en ES5. Es Vanilla JS y se lee mucho mejor que confiar en los padres.

Todos los navegadores modernos son compatibles.

Compatibilidad con navegador : 97 % junio de 21

Gibolt avatar Nov 15 '2016 09:11 Gibolt

La respuesta actualmente aceptada es incorrecta acerca innerHTMLde ser más lenta (al menos en IE y Chrome), como mencionó correctamente m93a.

Chrome y FF son dramáticamente más rápidos usando este método (que destruirá los datos jquery adjuntos):

var cNode = node.cloneNode(false);
node.parentNode.replaceChild(cNode, node);

en un distante segundo lugar para FF y Chrome, y el más rápido en IE:

node.innerHTML = '';

InnerHTML no destruirá sus controladores de eventos ni romperá las referencias de jquery ; también se recomienda como solución aquí: https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML .

El método de manipulación DOM más rápido (aún más lento que los dos anteriores) es la eliminación de rangos, pero los rangos no son compatibles hasta IE9.

var range = document.createRange();
range.selectNodeContents(node);
range.deleteContents();

Los otros métodos mencionados parecen ser comparables, pero mucho más lentos que internalHTML, excepto por el valor atípico, jquery (1.1.1 y 3.1.1), que es considerablemente más lento que cualquier otra cosa:

$(node).empty();

Evidencia aquí:

http://jsperf.com/innerhtml-vs-removechild/167 http://jsperf.com/innerhtml-vs-removechild/300 https://jsperf.com/remove-all-child-elements-of-a- dom-node-in-javascript (Nueva URL para reiniciar jsperf porque editar la URL anterior no funciona)

El "bucle por prueba" de Jsperf a menudo se entiende como "por iteración", y solo la primera iteración tiene nodos que eliminar, por lo que los resultados no tienen sentido. En el momento de la publicación, había pruebas en este hilo configuradas incorrectamente.

npjohns avatar Apr 09 '2014 15:04 npjohns