DOM을 여러 부모에 appendChild할 때의 문제점
✒️ 2025-05-23 17:06 내용 수정
참고 자료 : stackoverflow why-does-appendchild-moves-a-node, mdn web docs cloneNode, mdn web docs DOM, mdn web docs appendChild
문제 상황
- HTML 문서에 같은 class를 가지는 요소가 2개 존재하는데,
querySelectorAll()로 요소를 가져왔을 때 배열에는 요소가 2개 있는 것을 확인했다. - 그러나 배열의 첫번째 요소에만
appendChild()/prepend()가 적용되는 문제가 발생했다.
<section id="primary">
<div class="related-box"></div>
</section>
<!-- 중략 -->
<aside id="secondary">
<div class="related-box"></div>
</aside>
temp_div.innerHTML = data;
// 템플릿
const template = temp_div.querySelector("#scroll-menu").content;
// 스크롤 메뉴 전체 박스
const scroll_wrap = template.querySelector(".scroll-menu-wrap");
// video.html에서 메뉴 목록을 넣을 위치
// 2개의 요소가 들어온다.
const target = document.querySelectorAll(".related-container");
// 템플릿에서 목록 아이템을 넣을 위치
const menu_list = scroll_wrap.querySelector(".menu-list");
video_menu.forEach(el => {
// 리스트 아이템
const item = document.createElement("li");
// 버튼 태그
const item_btn = document.createElement("button");
item_btn.textContent = el.name_ko;
item.classList.add("menu-item-btn");
item.appendChild(item_btn);
menu_list.appendChild(item);
});
// need fix : 첫 번째에만 들어가는 문제 발생
target.forEach(el=>{
el.prepend(scroll_wrap)
});
원인 분석 및 해결 방법
- DOM은 한 번의 하나의 요소만 존재할 수 있다.
- 문서에 노드가 동시에 같은 두 포인트에 있을 수 없다.
appendChild()는 특정 부모의 노드가 가진 자식 노드들 리스트 중 맨 마지막에 노드를 추가한다.- 만약 자식 노드가 이미 문서에 존재하는 노드의 리퍼런스라면,
appendChild()는 그 노드를 다른 곳으로 옮긴다.- 따라서 DOM을 이미 다른 부모에
appendChild()하면, 다른 부모에appendChild()를 할 경우 복제되는 것이 아니라 원본 DOM을 다시 옮긴다.
- 따라서 DOM을 이미 다른 부모에
- 동일한 DOM을 여러 부모 노드에 넣으려면
cloneNode()로 DOM을 복제해서 넣어야 한다.
// 여러 개 넣을 요소를 복제해서 추가한다.
target.forEach(el=>{
el.prepend(clone.cloneNode(true));
});