HOWTO · JavaScript
JavaScript를 사용하여 기존 HTML 요소에 HTML 콘텐츠 추가
이 자습서에서는 JavaScript를 사용하여 HTML을 추가하는 방법을 자세히 설명합니다.
이 페이지의 내용
기존 요소에 콘텐츠를 추가할 때는 가진 데이터에 맞춰 API를 선택하세요. DOM 노드를 추가하려면 appendChild()를 사용하고, HTML 문자열을 파싱해 원하는 위치에 삽입하려면 insertAdjacentHTML()을 사용합니다. innerHTML에 값을 할당하면 요소의 하위 노드가 교체되므로 기존 자식을 보존하는 방법으로는 적합하지 않습니다.
innerHTML로 새 HTML 노드를 추가할 때의 단점
요소의 innerHTML에 문자열을 설정하면 해당 문자열이 파싱되고 요소의 하위 노드가 교체됩니다. 이 과정에서 하위 노드가 가진 상태나 해당 노드에 직접 연결된 이벤트 리스너가 사라질 수 있습니다. 그렇다고 대상 요소의 모든 속성이 제거되는 것은 아닙니다. 대상 요소 자체는 그대로 남고 자식 노드만 교체됩니다.
innerHTML과 insertAdjacentHTML()은 모두 문자열을 마크업으로 파싱합니다. 문자열에 신뢰할 수 없는 입력이 포함되면 사이트 간 스크립팅(XSS) 위험이 생길 수 있습니다. 노드를 직접 만들고 textContent 같은 텍스트 속성에 사용자 제공 값을 설정하는 편이 좋습니다. 마크업을 삽입해야 한다면 애플리케이션에 적합한 방식으로 정제하세요. MDN의 innerHTML 보안 고려 사항을 참고하세요.
DOM 요소를 교체하지 않고 HTML 콘텐츠 추가하기
새 요소를 만들 때는 노드를 생성해 기존 트리에 삽입하세요. 신뢰할 수 있는 HTML 문자열이라면 insertAdjacentHTML()을 사용하고 삽입 위치를 지정하면 됩니다. 이 방법들은 대상 요소의 기존 하위 노드를 교체하지 않고 콘텐츠를 추가합니다. 아래 예제에서는 작은 주소 입력 폼으로 두 방법을 보여 줍니다.
appendChild()로 JavaScript에서 HTML 콘텐츠 추가하기
appendChild()는 HTML 문자열이 아니라 노드를 받습니다. 대상 요소의 현재 마지막 자식 뒤에 해당 노드를 추가합니다. 노드가 문서의 다른 위치에 이미 있다면 복사본을 만드는 대신 같은 노드를 옮깁니다.
예제를 실행해 보세요.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
function addAddressLine(addressContainer, lineCount) {
const input = document.createElement("input");
input.type = "text";
input.placeholder = `Address Line ${lineCount}`;
addressContainer.appendChild(input);
}
if (typeof document !== "undefined") {
let lineCount = 0;
const button = document.getElementById("add-address");
const addressContainer = document.getElementById("address");
button.addEventListener("click", () => {
addAddressLine(addressContainer, ++lineCount);
});
}
폼의 요소를 조회하기 전에 해당 요소들이 만들어져 있어야 하므로, 스크립트를 폼 뒤에 두거나 defer로 불러오세요.
<form>
<label>Name: <input id="name" type="text"></label>
<div id="address">
<label>Address: <input id="contact" type="text"></label>
</div>
<button id="add-address" type="button">Add Address Line</button>
</form>
클릭 핸들러는 줄 번호를 하나씩 늘리고 address 요소에 새 텍스트 입력란을 추가합니다. 기존 이름 및 주소 입력란은 그대로 유지됩니다. type="button" 속성이 있어 버튼을 눌러도 폼이 제출되지 않습니다.
메모
또 다른 방법으로 append()를 사용할 수 있습니다. 이 메서드는 노드와 문자열 텍스트를 받지만, 문자열 인수는 HTML로 파싱되지 않고 텍스트로 삽입됩니다. 반환된 노드를 사용하거나 기존의 단일 노드 삽입 작업이 필요한 코드에서는 appendChild()를 사용하세요. 여기서는 브라우저 지원 범위를 다루지 않습니다. 애플리케이션에서 특정 브라우저 지원이 필요하다면 대상 브라우저를 확인하세요.
insertAdjacentHTML()로 특정 위치에 HTML 삽입하기
target.insertAdjacentHTML(position, htmlString)을 호출하면 문자열을 파싱해 target을 기준으로 마크업을 삽입합니다.
beforebegin은 대상 요소 바로 앞에 삽입합니다. 대상 요소에 부모가 있어야 합니다.afterbegin은 대상 요소 안에서 첫 번째 자식 앞에 삽입합니다.beforeend는 대상 요소 안에서 마지막 자식 뒤에 삽입합니다. 마크업을 덧붙일 때 사용하는 위치입니다.afterend는 대상 요소 바로 뒤에 삽입합니다. 대상 요소에 부모가 있어야 합니다.
예를 들어, 다음 코드는 주소 컨테이너의 끝에 새 주소 입력란을 삽입합니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
if (typeof document !== "undefined") {
const addressContainer = document.getElementById("address");
addressContainer.insertAdjacentHTML(
"beforeend",
'<input type="text" placeholder="Additional address line">'
);
}
appendChild()와 달리 이 메서드는 두 번째 인수를 HTML로 파싱합니다. 문자열을 신뢰할 수 있거나 안전하게 정제한 경우에만 사용하세요. 신뢰할 수 없는 텍스트를 마크업 문자열에 이어 붙이지 마세요. 사용자가 입력한 콘텐츠라면 요소를 만든 뒤 textContent나 그 밖의 적절한 속성을 설정하고 해당 노드를 추가하세요.