如何使用JavaScript将所有HTML元素子级移动到另一个父级?


80

想像:

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

old-parentnew-parent不使用jQuery的情况下,可以编写哪种JavaScript将所有子节点(元素和文本节点)从移到?

我不在乎节点之间的空格,尽管我希望能抓住一些麻烦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列表的所有元素从“待处理”父元素移动到“完成”父元素。
德鲁·诺阿克斯

Answers:


123

演示

基本上,您想遍历旧父节点的每个直接后代,并将其移动到新父节点。直接后代的任何子代都将随之移动。

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 2015年

4
注意,childNodes []通常也包含空的文本节点(源代码中的每个换行符都包含一个)。
Dercsár

5
@Gibolt我创建了一个JSPerf测试,似乎对我来说表明数组访问比调用更快firstChild。差异至多可以忽略不计。可能会因浏览器而异。我认为firstChild这更具可读性。
暗恋

17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);工作在2倍和铬快6倍至10倍的Firefox快。您修改过的JSPerf
用户

2
如果您追求性能,使用DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment并一次移动所有元素可能会有所帮助。
伊尔默

8

这是一个简单的函数:

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

elchildNodes要移动的元素, 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

8

现代方式:

newParent.append(...oldParent.childNodes);
  1. .append是的替代品.appendChild。主要区别在于它一次接受多个节点,甚至接受纯字符串,例如.append('hello!')
  2. oldParent.childNodes可迭代的,因此可以扩展...成为多个参数.append()

两者的兼容性表(简而言之:Edge 17 +,Safari 10+):


看起来很优雅。我想知道这里的其他答案是否存在性能差异。
Drew Noakes

如果有,则必须最小。如果有的话,它会更快,因为它是一个append 呼叫而不是多个呼叫。
fregante

被警告:不适用于IE11(可能永远不会)
Rene van der Lende

不错,但是我做了一些简单的测试,但while()在Chrome中仍然略快。不要相信我,如果可能,请执行自己的测试。
lepe

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字符串进行序列化/反序列化,但是这种方法有效。它确实起作用:)
Drew Noakes 2014年

11
它不会复制任何附加到元素上的对象和事件
Gregory Magarshak 2014年

4
这种重新生成的DOM,它不会移动现有的节点/事件,并且它可能比循环在所有子节点上都慢得多
约旦

我进行了一些简单的测试,这种方法仍然比公认的答案慢,并且它有缺点,如前所述。
lepe

-1

如果您不使用-ID的名称,则可以执行此操作

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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.