Wie verschiebe ich alle untergeordneten HTML-Elementelemente mit JavaScript auf ein anderes übergeordnetes Element?

80

Vorstellen:

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

Welches JavaScript kann geschrieben werden, um alle untergeordneten Knoten (sowohl Elemente als auch Textknoten) von old-parentnach zu verschieben?new-parent , ohne jQuery?

Leerzeichen zwischen Knoten sind mir egal, obwohl ich davon ausgehe Hello World, dass sie den Streuner auffangen , müssten sie auch so wie sie sind migriert werden.

BEARBEITEN

Um klar zu sein, möchte ich am Ende Folgendes haben:

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

Die Antwort auf die Frage, aus der dies ein vorgeschlagenes Duplikat ist, würde ergeben:

<div id="new-parent">
    <div id="old-parent">
        <span>Foo</span>
        <b>Bar</b>
        Hello World
    </div>
</div>
Drew Noakes
quelle
6
@MarcB, dies ist kein Duplikat. Die Frage, auf die Sie verlinken, befasst sich weder mit dem Verschieben aller Kinder noch mit einer Antwort auf diese Frage, die sich mit meiner Notwendigkeit befasst, verschiedene Arten von HTML-Knoten (z. B. Textknoten) zu verschieben.
Drew Noakes
2
Die Antwort ist genau das, was Sie brauchen. dom ist ein Baum. Verschieben Sie einen Knoten, alle untergeordneten Knoten dieses Knotens bewegen sich mit.
Marc B
@MarcB Manchmal möchten Sie das übergeordnete Objekt nicht im Ziel haben. Ziehen Sie beispielsweise in Betracht, alle Elemente einer TODO-Liste von den ausstehenden übergeordneten zu den übergeordneten Elementen zu verschieben.
Drew Noakes

Antworten:

123

DEMO

Grundsätzlich möchten Sie jeden direkten Nachkommen des alten übergeordneten Knotens durchlaufen und auf den neuen übergeordneten Knoten verschieben. Alle Kinder eines direkten Nachkommen werden damit bewegt.

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

while (oldParent.childNodes.length > 0) {
    newParent.appendChild(oldParent.childNodes[0]);
}
zerquetschen
quelle
8
Um wirklich effizient zu sein: while (oldParent.childNodes.length) { newParent.appendChild(oldParent.firstChild); }
Gibolt
4
Beachten Sie, dass childNodes [] normalerweise auch leere Textknoten enthält (einen für jeden Zeilenumbruch im Quellcode).
Dercsár
5
@ Gibolt Ich habe einen JSPerf- Test erstellt und es scheint mir anzuzeigen, dass der Array-Zugriff schneller ist als das Aufrufen firstChild. Der Unterschied ist bestenfalls vernachlässigbar. Es wird wahrscheinlich auch von Browser zu Browser unterschiedlich sein. Ich denke firstChildaber besser lesbar.
Crush
17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);und while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);arbeiten 2x schneller in Chromium und 6x bis 10x schneller in Firefox. Ihr modifizierter JSPerf
Benutzer
2
Es kann nützlich sein, DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment zu verwenden und alle Elemente auf einmal zu verschieben, wenn Sie nach der Leistung sind.
Mhor Mé
8

Hier ist eine einfache Funktion:

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

el's childNodessind die Elemente, die verschoben werden sollen, newParent ist das Element, elin das verschoben werden soll, so dass Sie die Funktion wie folgt ausführen würden:

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);
}

Hier ist die Demo

Cilan
quelle
Wie würden Sie dies mit seinem Code verwenden? Dies würde das old-parentElement auch verschieben, wenn Sie das als übergeben el.
Crush
1
Das würde HTML rendern:<div id="new-parent"><div id="old-parent">...</div></div>
Crush
1
Das funktioniert auch nicht, denn wenn Sie das Kind bewegen, ändert sich die Länge. Sie werden also nur die Hälfte der Knoten verschieben. Sie müssen rückwärts iterieren oder eine while-Schleife verwenden, wie ich es getan habe.
Crush
Funktioniert immer noch nicht. Sie müssen tun: for (var i = l; i >= 0; i--)oder while (document.getElementById('old-parent').length > 0). Außerdem enthält Ihre Demo Fehler.
Crush
@ Crush Blick auf bearbeiten, sry -while (document.getElementById('old-parent').length > 0) { setParent(document.getElementById('old-parent')[i], document.getElementById('new-parent')); }
Cilan
8

Moderne Art:

newParent.append(...oldParent.childNodes);
  1. .appendist der Ersatz für .appendChild. Der Hauptunterschied besteht darin, dass mehrere Knoten gleichzeitig und sogar einfache Zeichenfolgen akzeptiert werden.append('hello!')
  2. oldParent.childNodesist iterierbar, so dass es mit ...mehreren Parametern von verbreitet werden kann.append()

Kompatibilitätstabellen von beiden (kurz: Edge 17+, Safari 10+):

fregante
quelle
Sieht sehr elegant aus. Ich frage mich, ob es einen Leistungsunterschied zu den anderen Antworten hier gibt.
Drew Noakes
Wenn ja, muss es minimal sein. Wenn überhaupt, ist es schneller, weil es ein einzelner append Anruf statt vieler ist.
Fregante
Seien Sie gewarnt: nicht für IE11 (wahrscheinlich nie)
Rene van der Lende
Schön, aber ich habe einige einfache Tests durchgeführt und while()ist in Chrome immer noch etwas schneller. Nehmen Sie nicht mein Wort und führen Sie wenn möglich Ihre eigenen Tests durch.
Lepe
0

Diese Antwort funktioniert nur dann wirklich, wenn Sie nichts anderes tun müssen, als den inneren Code (innerHTML) von einem zum anderen zu übertragen:

// 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 = '';

Hoffe das hilft!

ItsJonQ
quelle
1
Dies funktioniert, obwohl ich nicht wirklich über HTML-Strings serialisieren / deserialisieren möchte. Es funktioniert aber :)
Drew Noakes
11
Es werden keine der Objekte und Ereignisse kopiert, die mit den Elementen verbunden sind
Gregory Magarshak
4
Dieses regenerierte DOM verschiebt keine vorhandenen Knoten / Ereignisse und ist wahrscheinlich viel langsamer als eine Schleife für alle Kinder
Jordanien
Ich habe einige einfache Tests durchgeführt und diese Methode ist immer noch langsamer als die akzeptierte Antwort und hat, wie bereits erläutert, Nachteile.
Lepe
-1

Wenn Sie -die Namen der ID nicht verwenden , können Sie dies tun

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>

Kamil Kiełczewski
quelle