Как переместить все дочерние элементы 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
ответ именно то, что вам нужно. дом - это дерево. переместите один узел, все дочерние элементы этого узла перемещаются вместе с ним.
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); }
Gibolt 02

4
Обратите внимание, что childNodes [] обычно также содержит пустые текстовые узлы (по одному на каждый разрыв строки в исходном коде).
Dercsár,

5
@Gibolt Я создал тест JSPerf, и мне кажется, что это указывает на то, что доступ к массиву выполняется быстрее, чем вызов firstChild. Разница в лучшем случае незначительна. Вероятно, это также будет отличаться от браузера к браузеру. Я думаю, что firstChildэто более читабельно.
Crush

17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);и while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);работайте в 2 раза быстрее в Chromium и в 6-10 раз быстрее в Firefox. Ваш измененный JSPerf
пользователь

3
Может быть полезно использовать DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment и перемещать все элементы сразу, если вам нужна производительность.
hor Mé

10

Современный способ:

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

Таблицы совместимости обоих (кратко: Edge 17+, Safari 10+):


Выглядит очень элегантно. Интересно, есть ли здесь разница в производительности с другими ответами.
Дрю Ноукс

Если есть, то он должен быть минимальным. Во всяком случае, это быстрее, потому что это один append звонок вместо множества.
fregante 08

Предупреждаем: не для IE11 (никогда, наверное)
Рене ван дер Ленде

Хорошо, но я провел несколько простых тестов и while()все еще немного быстрее в Chrome. Не верьте мне на слово и, если возможно, проведите свои собственные тесты.
lepe

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.
Crush

1
Это сделало бы HTML:<div id="new-parent"><div id="old-parent">...</div></div>
раздавить

1
Это тоже не сработает, потому что, когда вы двигаете ребенка, длина меняется. Таким образом, вы переместите только половину узлов. Вам нужно выполнить итерацию в обратном направлении или использовать цикл while, как я.
Crush

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

@crush, посмотрите на редактирование, извините -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, он не перемещает существующие узлы / события и, вероятно, намного медленнее, чем цикл для всех детей
Джордан

Я провел несколько простых тестов, и этот метод все еще медленнее, чем принятый ответ, и у него есть недостатки, как уже объяснялось.
lepe

-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.