Jak przenieść wszystkie dzieci elementów HTML do innego rodzica za pomocą JavaScript?


80

Wyobrażać sobie:

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

Jaki JavaScript można napisać, aby przenieść wszystkie węzły potomne (zarówno elementy, jak i węzły tekstowe) z old-parentdo new-parentbez jQuery?

Nie obchodzą mnie spacje między węzłami, chociaż spodziewam się, że złapię zbłąkane Hello World, musiałyby zostać przeniesione tak, jak są.

EDYTOWAĆ

Żeby było jasne, chcę skończyć z:

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

Odpowiedź na pytanie, z którego jest to proponowany duplikat, skutkowałaby:

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


6
@MarcB, to nie jest duplikat. Pytanie, do którego odsyłasz, nie dotyczy przenoszenia wszystkich dzieci, ani żadna odpowiedź na to pytanie nie rozwiązuje mojej potrzeby przenoszenia różnych typów węzłów HTML (takich jak węzły tekstowe).
Drew Noakes

2
odpowiedź jest dokładnie tym, czego potrzebujesz. dom to drzewo. przesuń jeden węzeł, wszystkie elementy podrzędne tego węzła poruszają się wraz z nim.
Marc B,

@MarcB czasami nie chcesz, aby obiekt nadrzędny znalazł się w miejscu docelowym. Rozważmy na przykład przeniesienie wszystkich elementów listy TODO z elementów nadrzędnych „oczekujących” do „ukończonych”.
Drew Noakes

Odpowiedzi:


124

PRÓBNY

Zasadniczo chcesz przejść przez każdy bezpośredni potomek starego węzła nadrzędnego i przenieść go do nowego węzła nadrzędnego. Wszelkie dzieci bezpośredniego potomka zostaną nim poruszone.

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

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

8
Aby być naprawdę wydajnym: while (oldParent.childNodes.length) { newParent.appendChild(oldParent.firstChild); }
Gibolt

4
Zauważ, że childNodes [] zwykle zawiera również puste węzły tekstowe (po jednym na każdy podział wiersza w kodzie źródłowym).
Dercsár

5
@Gibolt Stworzyłem test JSPerf i wydaje mi się, że wskazuje mi, że dostęp do tablicy jest szybszy niż wywołanie firstChild. W najlepszym przypadku różnica jest znikoma. Prawdopodobnie będzie się to również różnić w zależności od przeglądarki. Myślę jednak, że firstChildjest bardziej czytelny.
zmiażdżyć

17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);i while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);pracuj 2x szybciej w Chromium i od 6x do 10x szybciej w Firefoksie. Twój zmodyfikowany JSPerf
użytkownik

3
Korzystne może być użycie DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment i przeniesienie wszystkich elementów naraz, jeśli zależy Ci na wydajności.
Íhor Mé

10

Nowoczesny sposób:

newParent.append(...oldParent.childNodes);
  1. .appendjest zamiennikiem .appendChild. Główną różnicą jest to, że akceptuje wiele węzłów jednocześnie, a nawet zwykłe ciągi, takie jak.append('hello!')
  2. oldParent.childNodes jest iterowalny, więc można go rozprzestrzeniać, ...aby stać się wieloma parametrami.append()

Tabele kompatybilności obu (w skrócie: Edge 17+, Safari 10+):


Wygląda bardzo elegancko. Zastanawiam się, czy istnieje różnica w wydajności w stosunku do innych odpowiedzi tutaj.
Drew Noakes

Jeśli tak, to musi być minimalne. Jeśli już, to jest szybsze, ponieważ jest to jedno append połączenie zamiast wielu.
fregante

Uwaga: nie dla IE11 (nigdy, prawdopodobnie)
Rene van der Lende

Fajnie, ale zrobiłem kilka prostych testów i while()nadal jest trochę szybszy w Chrome. Nie wierz mi na słowo i jeśli to możliwe, wykonuj własne testy.
lepe

8

Oto prosta funkcja:

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

el„s childNodeselementy do przeniesienia, newParent jest elementem elzostaną przeniesione, więc można wykonać funkcji takich jak:

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

Oto Demo


Jak użyłbyś tego z jego kodem? Spowoduje to również przesunięcie old-parentelementu, jeśli podasz go jako el.
zmiażdżyć

1
To wyrenderowałoby HTML:<div id="new-parent"><div id="old-parent">...</div></div>
zmiażdżył

1
To też nie zadziała, ponieważ gdy poruszasz dzieckiem, długość się zmienia. W rezultacie przesuniesz tylko połowę węzłów. Musisz wykonać iterację wstecz lub użyć pętli while, tak jak ja.
zmiażdżyć

Nadal nie zadziała. Musisz zrobić: for (var i = l; i >= 0; i--)lub while (document.getElementById('old-parent').length > 0). Twoje demo zawiera również błędy.
zmiażdżyć

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

0

Ta odpowiedź naprawdę działa tylko wtedy, gdy nie musisz robić nic innego niż przenoszenie kodu wewnętrznego (innerHTML) z jednego na drugi:

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

Mam nadzieję że to pomoże!


1
To działa, chociaż tak naprawdę nie chcę serializować / deserializować za pomocą ciągów HTML. To jednak działa :)
Drew Noakes

11
Nie skopiuje żadnych obiektów i wydarzeń dołączonych do elementów
Gregory Magarshak,

4
Ta regeneracja DOM, nie przenosi istniejących węzłów / zdarzeń i prawdopodobnie jest znacznie wolniejsza niż pętla na wszystkich
Jordan,

Przeprowadziłem kilka prostych testów i ta metoda jest nadal wolniejsza niż akceptowana odpowiedź i ma wady, jak już wyjaśniono.
lepe

-1

Jeśli nie używasz -w nazwach id, możesz to zrobić

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>

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.