¿Cómo mover todos los elementos secundarios HTML a otro padre usando JavaScript?


80

Imagina:

<div id="old-parent">
    <span>Foo</span>
    <b>Bar</b>
    Hello World
</div>
<div id="new-parent"></div>

¿Qué JavaScript se puede escribir para mover todos los nodos secundarios (tanto elementos como nodos de texto) de old-parenta new-parentsin jQuery?

No me importa el espacio en blanco entre los nodos, aunque espero atrapar a los extraviados Hello World, también tendrían que migrarlos como están.

EDITAR

Para ser claro, quiero terminar con:

<div id="old-parent"></div>
<div id="new-parent">
    <span>Foo</span>
    <b>Bar</b>
    Hello World
</div>

La respuesta a la pregunta de la que se trata de un duplicado propuesto resultaría en:

<div id="new-parent">
    <div id="old-parent">
        <span>Foo</span>
        <b>Bar</b>
        Hello World
    </div>
</div>


6
@MarcB, esto no es un duplicado. La pregunta a la que enlaza no trata de mover a todos los niños, ni ninguna respuesta a esa pregunta aborda mi necesidad de mover diferentes tipos de nodos HTML (como nodos de texto).
— Drew Noakes

2
la respuesta es exactamente lo que necesita. dom es un árbol. mueve un nodo, todos los hijos de ese nodo se mueven con él.
— Marc B

@MarcB a veces no desea que el objeto principal en el destino. Considere, por ejemplo, mover todos los elementos de una lista TODO de los elementos principales 'pendientes' a 'completos'.
— Drew Noakes

Respuestas:


124

MANIFESTACIÓN

Básicamente, desea recorrer cada descendiente directo del nodo padre antiguo y moverlo al nuevo padre. Cualquier hijo de un descendiente directo se moverá con él.

var newParent = document.getElementById('new-parent');
var oldParent = document.getElementById('old-parent');

while (oldParent.childNodes.length > 0) {
    newParent.appendChild(oldParent.childNodes[0]);
}

8
Para ser realmente eficiente: while (oldParent.childNodes.length) { newParent.appendChild(oldParent.firstChild); }
— Gibolt

4
Tenga en cuenta que childNodes [] normalmente también contiene nodos de texto vacíos (uno por cada salto de línea en el código fuente).
— Dercsár

5
@Gibolt Creé una prueba JSPerf y parece indicarme que el acceso a la matriz es más rápido que llamar firstChild. La diferencia es insignificante en el mejor de los casos. Probablemente también variará de un navegador a otro. Sin firstChildembargo, creo que es más legible.
— aplastar

17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);y while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);trabaja 2 veces más rápido en Chromium y de 6 a 10 veces más rápido en Firefox. Su JSPerf modificado
— usuario

2
Puede ser beneficioso utilizar DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment y mover todos los elementos a la vez si lo que busca es rendimiento.
— Íhor Mé

9

Manera moderna:

newParent.append(...oldParent.childNodes);
  1. .appendes el reemplazo de .appendChild. La principal diferencia es que acepta varios nodos a la vez e incluso cadenas simples, como.append('hello!')
  2. oldParent.childNodeses iterable, por lo que puede extenderse ...para convertirse en múltiples parámetros de.append()

Tablas de compatibilidad de ambos (en resumen: Edge 17+, Safari 10+):


Parece muy elegante. Me pregunto si hay una diferencia de rendimiento con las otras respuestas aquí.
— Drew Noakes

Si lo hay, debe ser mínimo. En todo caso, es más rápido porque es una sola append llamada en lugar de muchas.
— fregante

Tenga cuidado: no para IE11 (nunca, probablemente)
— Rene van der Lende

Bien, pero hice algunas pruebas simples y while()todavía es un poco más rápido en Chrome. No tome mi palabra y realice sus propias pruebas si es posible.
— lepe

8

Aquí tienes una función simple:

function setParent(el, newParent)
{
    newParent.appendChild(el);
}

el's childNodesson los elementos que se moverán, newParent es el elemento al elque se moverá, por lo que ejecutaría la función como:

var l = document.getElementById('old-parent').childNodes.length;
var a = document.getElementById('old-parent');
var b = document.getElementById('new-parent');
for (var i = l; i >= 0; i--)
{
    setParent(a.childNodes[0], b);
}

Aquí está la demostración


¿Cómo usarías esto con su código? Esto también movería el old-parentelemento si lo pasara como el.
— aplastar el

1
Eso representaría HTML:<div id="new-parent"><div id="old-parent">...</div></div>
— aplastar el

1
Eso tampoco funcionará porque a medida que mueve al niño, la longitud cambia. Entonces, terminarás moviendo solo la mitad de los nodos. Necesita iterar hacia atrás o usar un ciclo while como lo hice yo.
— aplastar el

Todavía no funcionará. Necesita hacer: for (var i = l; i >= 0; i--)o while (document.getElementById('old-parent').length > 0). Además, su demostración tiene errores.
— aplastar el

@crush mira editar, sry -while (document.getElementById('old-parent').length > 0) { setParent(document.getElementById('old-parent')[i], document.getElementById('new-parent')); }
— Cilan

0

Esta respuesta solo funciona realmente si no necesita hacer nada más que transferir el código interno (innerHTML) de uno a otro:

// Define old parent
var oldParent = document.getElementById('old-parent');

// Define new parent
var newParent = document.getElementById('new-parent');

// Basically takes the inner code of the old, and places it into the new one
newParent.innerHTML = oldParent.innerHTML;

// Delete / Clear the innerHTML / code of the old Parent
oldParent.innerHTML = '';

¡Espero que esto ayude!


1
Esto funciona, aunque realmente no quiero serializar / deserializar a través de cadenas HTML. Aunque funciona :)
— Drew Noakes

11
No copiará ninguno de los objetos y eventos adjuntos a los elementos
— Gregory Magarshak

4
Este DOM regenerado, no mueve nodos / eventos existentes y probablemente es mucho más lento que un bucle en todos los niños
— Jordan

Ejecuté algunas pruebas simples y este método aún es más lento que la respuesta aceptada, y tiene desventajas como ya se explicó.
— lepe

-1

Si no lo usa -en los nombres de identificación, puede hacer esto

oldParent.id='xxx';
newParent.id='oldParent';
xxx.id='newParent';
oldParent.parentNode.insertBefore(oldParent,newParent);
#newParent { color: red }
<div id="oldParent">
    <span>Foo</span>
    <b>Bar</b>
    Hello World
</div>
<div id="newParent"></div>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.