Eliminar todos los elementos secundarios de un nodo DOM en JavaScript
¿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 foo
para 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.
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>
Opción 1 B: CompensacióntextContent
- Como arriba, pero use
.textContent
. Según MDN, esto será más rápido ya queinnerHTML
los navegadores no invocarán sus analizadores HTML y, en su lugar, reemplazarán inmediatamente todos los elementos secundarios del elemento con un solo#text
nodo.
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>
Opción 2 A: bucle para eliminar cada lastChild
:
- Se utilizó una edición anterior de esta respuesta
firstChild
, pero se actualizó para usarlalastChild
como 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 verificarlolastChild
(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>
Opción 2 B: bucle para eliminar cada lastElementChild
:
- Este enfoque preserva todos los nodos
Element
(es decir,#text
nodos 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
lastElementChild
IE9.
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>
Bono: Element.clearChildren
parche de mono:
- Podemos agregar una nueva propiedad de método al
Element
prototipo en JavaScript para simplificar su invocación a soloel.clearChildren()
(dóndeel
está 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>
¡En 2022+, use la replaceChildren()
API!
Ahora se puede reemplazar a todos los niños con la replaceChildren
API (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.
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
La respuesta actualmente aceptada es incorrecta acerca innerHTML
de 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.