Як перенести всі дочірні елементи HTML до іншого батька за допомогою JavaScript?


80

Уявіть:

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

Який JavaScript можна записати для переміщення всіх дочірніх вузлів (як елементів, так і текстових вузлів) з old-parentдо new-parentбез jQuery?

Мені байдуже пробіл між вузлами, хоча я сподіваюся, що зловмисне Hello World, їх також потрібно буде перенести як є.

РЕДАГУВАТИ

Щоб бути зрозумілим, я хочу закінчити з:

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

Відповідь на запитання, з якого це пропонований дублікат, призведе до:

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


6
@MarcB, це не дублікат. Питання, на яке ви посилаєтесь, не стосується переміщення всіх дітей, а також жодна відповідь на це запитання не стосується моєї потреби в переміщенні різних типів вузлів HTML (наприклад, текстових вузлів).
Дрю Ноукс,

2
відповідь - саме те, що вам потрібно. dom - це дерево. перемістити один вузол, всі дочірні елементи цього вузла рухаються разом з ним.
Marc B

@MarcB іноді ви не хочете батьківський об'єкт у місці призначення. Розглянемо, наприклад, переміщення всіх елементів списку TODO із батьківських елементів, що очікують на розгляд, у „повні”.
Дрю

Відповіді:


124

ДЕМО

В основному, ви хочете прокрутити кожен прямий нащадок старого батьківського вузла та перемістити його до нового батьківського. Будь-які діти прямого нащадка будуть рухатися разом з ним.

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

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

8
Щоб бути дійсно ефективним: while (oldParent.childNodes.length) { newParent.appendChild(oldParent.firstChild); }
Гіболт

4
Зверніть увагу, що childNodes [] зазвичай також містить порожні текстові вузли (по одному для кожного розриву рядка у вихідному коді).
Dercsár

5
@Gibolt Я створив тест JSPerf, і, здається, це вказує на мене, що доступ до масиву швидший, ніж виклик firstChild. Різниця в кращому випадку незначна. Можливо, це також буде відрізнятися від браузера до браузера. firstChildОднак я думаю, що це читабельніше.
розчавити

17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);і while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);працюйте вдвічі швидше в Chromium і в 6–10 разів швидше у Firefox. Ваш змінений JSPerf
користувач

2
Може бути корисним використання DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment і переміщення всіх елементів одночасно, якщо ви хочете виконати .
Íhor Mé

9

Сучасний спосіб:

newParent.append(...oldParent.childNodes);
  1. .appendє заміною .appendChild. Головна відмінність полягає в тому, що він приймає відразу кілька вузлів і навіть звичайні рядки, наприклад.append('hello!')
  2. oldParent.childNodesє ітераційним, тому його можна розповсюдити, ...щоб стати безліччю параметрів.append()

Таблиці сумісності обох (коротше: Edge 17+, Safari 10+):


Виглядає дуже елегантно. Цікаво, чи є різниця в ефективності інших відповідей тут.
Дрю

Якщо вона є, вона повинна бути мінімальною. У всякому разі це швидше, тому що це один append дзвінок замість багатьох.
fregante

Будьте застережені: не для IE11 (ніколи, мабуть)
Рене ван дер Ленде,

Приємно, але я провів кілька простих тестів і while()все одно трохи швидший у Chrome. Не вірте мені на слово і виконуйте власні тести, якщо це можливо.
лепе

8

Ось проста функція:

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

el's childNodes- це елементи, які потрібно перемістити, newParent - це елемент, до якого elбуде переміщено, тому ви виконаєте функцію, як:

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

Ось демонстрація


Як би ви використали це з його кодом? Це також перемістило б old-parentелемент, якщо ви передали його як el.
розчавити

1
Це зробило б HTML:<div id="new-parent"><div id="old-parent">...</div></div>
розчавити

1
Це також не спрацює, тому що, коли ви рухаєте дитину, довжина змінюється. Отже, ви в кінцевому підсумку перемістите лише половину вузлів. Вам потрібно виконати ітерацію назад або використовувати цикл while, як це робив я.
розчавити

Все одно не буде працювати. Вам потрібно зробити: for (var i = l; i >= 0; i--)або while (document.getElementById('old-parent').length > 0). Крім того, у вашому демо-файлі є помилки.
розчавити

@crush погляд на редагування, sry -while (document.getElementById('old-parent').length > 0) { setParent(document.getElementById('old-parent')[i], document.getElementById('new-parent')); }
Cilan

0

Ця відповідь справді працює лише в тому випадку, якщо вам не потрібно робити нічого, крім передачі внутрішнього коду (innerHTML) з одного в інший:

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

Сподіваюся, це допомагає!


1
Це працює, хоча я насправді не хочу серіалізувати / десеріалізувати за допомогою рядків HTML. Хоча це працює :)
Дрю Ноукс

11
Він не скопіює жодного об’єкта та події, прикріплених до елементів
Григорій Магаршак,

4
Цей регенерує DOM, він не переміщує існуючі вузли / події, і це, мабуть, набагато повільніше, ніж цикл для всіх дітей
Йорданія,

Я провів кілька простих тестів, і цей метод все ще повільніший за прийняту відповідь, і він має недоліки, як уже було пояснено.
лепе

-1

Якщо ви не використовуєте -імена ідентифікаторів, ви можете це зробити

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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.