Làm cách nào để chuyển tất cả phần tử con HTML sang phần tử gốc khác bằng JavaScript?


80

Hãy tưởng tượng:

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

JavaScript nào có thể được viết để di chuyển tất cả các nút con (cả phần tử và nút văn bản) từ old-parentchỗ new-parentkhông có jQuery?

Tôi không quan tâm đến khoảng trắng giữa các nút, mặc dù tôi hy vọng sẽ bắt được lỗi Hello World, chúng cũng sẽ cần được di chuyển.

BIÊN TẬP

Để rõ ràng, tôi muốn kết thúc bằng:

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

Câu trả lời của câu hỏi mà từ đó đây là một bản sao được đề xuất sẽ dẫn đến:

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


6
@MarcB, đây không phải là bản sao. Các câu hỏi mà bạn liên kết đến không đối phó với di chuyển tất cả trẻ em, cũng không bất kỳ câu trả lời trên địa chỉ câu hỏi của tôi cần phải di chuyển các loại khác nhau của nút HTML (ví dụ như các nút văn bản.)
Drew Noakes

2
câu trả lời là chính xác những gì bạn cần. dom là một cái cây. di chuyển một nút, tất cả các nút con của nút đó di chuyển cùng với nó.
Marc B

@MarcB đôi khi bạn không muốn đối tượng cha trong đích. Hãy xem xét ví dụ di chuyển tất cả các phần tử của danh sách VIỆC CẦN LÀM từ các phần tử mẹ 'đang chờ xử lý' sang 'hoàn thành'.
Drew Noakes

Câu trả lời:


124

BẢN GIỚI THIỆU

Về cơ bản, bạn muốn lặp qua từng nút con trực tiếp của nút cha cũ và chuyển nó sang nút cha mới. Bất kỳ đứa trẻ nào thuộc dòng dõi trực hệ sẽ cảm động với nó.

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

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

8
Để có thực sự hiệu quả: while (oldParent.childNodes.length) { newParent.appendChild(oldParent.firstChild); }
Gibolt

4
Lưu ý rằng mã con [] cũng thường chứa các nút văn bản trống (một nút cho mỗi ngắt dòng trong mã nguồn).
Dercsár

5
@Gibolt Tôi đã tạo một bài kiểm tra JSPerf và nó dường như cho tôi biết rằng truy cập mảng nhanh hơn việc gọi firstChild. Sự khác biệt tốt nhất là không đáng kể. Nó có thể cũng sẽ khác nhau giữa các trình duyệt. Tôi nghĩ firstChildlà dễ đọc hơn, mặc dù.
nghiền nát

17
while (oldParent.hasChildNodes()) newParent.appendChild(oldParent.firstChild);while (oldParent.firstChild) newParent.appendChild(oldParent.firstChild);hoạt động nhanh hơn gấp 2 lần trong Chromium và nhanh hơn 6 lần đến 10 lần trong Firefox. JSPerf đã sửa đổi của bạn
người dùng

2
Có thể có lợi khi sử dụng DocumentFragment developer.mozilla.org/en-US/docs/Web/API/DocumentFragment và di chuyển tất cả các phần tử cùng một lúc nếu bạn đang theo đuổi hiệu suất.
Íhor Mé

9

Cách hiện đại:

newParent.append(...oldParent.childNodes);
  1. .appendlà sự thay thế cho .appendChild. Sự khác biệt chính là nó chấp nhận nhiều nút cùng một lúc và thậm chí cả các chuỗi đơn giản, như.append('hello!')
  2. oldParent.childNodescó thể lặp lại nên nó có thể được trải rộng ...để trở thành nhiều tham số của.append()

Bảng tương thích của cả hai (ngắn gọn: Edge 17+, Safari 10+):


Trông rất thanh lịch. Tôi tự hỏi liệu có sự khác biệt về hiệu suất với các câu trả lời khác ở đây không.
Drew Noakes

Nếu có nó phải là tối thiểu. Nếu có gì thì nhanh hơn vì đó là một append cuộc gọi duy nhất thay vì nhiều cuộc gọi.
fregante

Được cảnh báo: không cho IE11 (không bao giờ, có lẽ)
Rene van der Lende

Tốt, nhưng tôi đã thực hiện một số thử nghiệm đơn giản và while()vẫn nhanh hơn một chút trong Chrome. Đừng nghe lời tôi và thực hiện các bài kiểm tra của riêng bạn nếu có thể.
lepe

8

Đây là một chức năng đơn giản:

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

el's childNodeslà những yếu tố để được di chuyển, newParentyếu tố elsẽ được chuyển đến, do đó bạn sẽ thực hiện các chức năng như:

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

Đây là bản Demo


Làm thế nào bạn sẽ sử dụng điều này với mã của anh ấy? Điều này cũng sẽ di chuyển old-parentphần tử nếu bạn vượt qua nó như el.
nghiền nát

1
Điều đó sẽ hiển thị HTML:<div id="new-parent"><div id="old-parent">...</div></div>
nghiền nát

1
Điều đó cũng sẽ không hiệu quả vì khi bạn di chuyển đứa trẻ, chiều dài sẽ thay đổi. Vì vậy, bạn sẽ chỉ di chuyển một nửa số nút. Bạn cần lặp ngược lại hoặc sử dụng vòng lặp while như tôi đã làm.
nghiền nát

Vẫn không hoạt động. Bạn cần làm: for (var i = l; i >= 0; i--)hoặc while (document.getElementById('old-parent').length > 0). Ngoài ra, bản demo của bạn có lỗi trong đó.
nghiền nát

@crush nhìn chỉnh sửa đi, sry -while (document.getElementById('old-parent').length > 0) { setParent(document.getElementById('old-parent')[i], document.getElementById('new-parent')); }
Cilan

0

Câu trả lời này chỉ thực sự hoạt động nếu bạn không cần phải làm gì khác ngoài việc chuyển mã bên trong (innerHTML) từ mã này sang mã khác:

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

Hi vọng điêu nay co ich!


1
Điều này hoạt động, mặc dù tôi không thực sự muốn serialise / deserialise qua chuỗi HTML. Mặc dù vậy nó vẫn hoạt động :)
Drew Noakes

11
Nó sẽ không sao chép bất kỳ của các đối tượng và các sự kiện gắn liền với các yếu tố
Gregory Magarshak

4
Điều này tạo lại DOM, nó không di chuyển các nút / sự kiện hiện có và nó có thể chậm hơn một vòng lặp trên tất cả các trẻ em
Jordan

Tôi đã chạy một số bài kiểm tra đơn giản và phương pháp này vẫn chậm hơn so với câu trả lời được chấp nhận và nó có những nhược điểm như đã được giải thích.
lepe

-1

Nếu bạn không sử dụng -tên của id thì bạn có thể làm điều này

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>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.