appendChild() 또는 insertBefore()과 같은 기존 메서드를 사용하여 DOM 요소를 다시 상위 요소로 지정하면 브라우저는 암시적으로 DOM에서 요소를 삭제한 다음 새 위치에 삽입합니다. 이 '삭제 및 삽입' 작업은 많은 내부 상태를 재설정하여 <iframe> 요소가 새로고침되고 CSS 애니메이션이 다시 시작되며 입력 필드가 포커스를 잃게 합니다.
상태를 유지하면서 요소를 이동하려면 moveBefore() API를 사용합니다. 이 메서드는 원자적 이동을 실행하여 삭제 및 삽입 단계를 완전히 우회합니다.
상태가 있는 요소 이동
insertBefore()를 사용하는 것과 동일하게 moveBefore()를 사용합니다. 이동할 노드와 앞에 삽입할 참조 노드 (또는 새 상위 노드의 끝에 추가할 null)라는 두 가지 인수가 필요합니다.
const newParent = document.getElementById('new-parent');
const elementWithState = document.getElementById('iframe-or-focused-input');
// MANDATORY: Use moveBefore to preserve state.
// Passing null as the second argument appends the element to the end of newParent.
newParent.moveBefore(elementWithState, null);
맞춤 요소 이동 (웹 구성요소)
moveBefore()를 사용하여 맞춤 요소를 이동하는 경우 connectedCallback 및 disconnectedCallback 수명 주기 메서드가 실행되지 않습니다.
커스텀 요소가 이동할 때 특정 로직을 실행해야 하는 경우 커스텀 요소 정의 내에 connectedMoveCallback() 메서드를 구현합니다.
class MyCustomElement extends HTMLElement {
connectedCallback() {
// Runs on initial insertion.
}
connectedMoveCallback() {
// Runs when the element is moved via moveBefore().
// Use this to update state that depends on the new DOM location.
}
}
대체 전략
moveBefore()는 점진적 개선이므로 호출하기 전에 기능 감지를 사용해야 하며, 이전 브라우저의 경우 기존 insertBefore() 또는 appendChild() 작업으로 대체해야 합니다.
const targetParent = document.getElementById('target-container');
const nodeToMove = document.getElementById('moving-element');
// Check if moveBefore is supported on the Element prototype
if ('moveBefore' in Element.prototype) {
targetParent.moveBefore(nodeToMove, null);
} else {
// Fallback: traditional move.
// Note: This WILL reset <iframe>, animation, and focus state in unsupported browsers.
targetParent.insertBefore(nodeToMove, null);
}