DOM 조작과 이벤트 처리 기초
DOM(Document Object Model)은 HTML 문서의 프로그래밍 인터페이스로, 웹 페이지의 내용, 구조, 스타일을 자바스크립트로 동적으로 변경할 수 있게 해줍니다.
이 절에서는 DOM 조작과 이벤트 처리의 기본 개념과 기법을 살펴보겠습니다.
DOM의 개념과 구조
DOM은 문서를 논리 트리로 표현합니다.
각 노드는 문서의 일부를 나타내며, 이 트리 구조를 통해 노드를 생성, 변경, 삭제할 수 있습니다.
DOM 요소 선택
- getElementById : ID로 단일 요소 선택
let element = document.getElementById('myId');
- querySelector : CSS 선택자로 첫 번째 일치 요소 선택
let element = document.querySelector('.myClass');
- querySelectorAll : CSS 선택자로 일치하는 모든 요소 선택
let elements = document.querySelectorAll('p');
DOM 조작
- 요소 생성
let newDiv = document.createElement('div');
- 텍스트 노드 생성
let textNode = document.createTextNode('Hello, World!');
newDiv.appendChild(textNode);
- 요소 추가
document.body.appendChild(newDiv);
- 요소 제거
let oldElement = document.getElementById('oldElement');
oldElement.parentNode.removeChild(oldElement);
- 속성 조작
element.setAttribute('class', 'highlight');
let classValue = element.getAttribute('class');
- 스타일 변경
element.style.color = 'red';
element.style.backgroundColor = '#f0f0f0';
이벤트 처리
이벤트는 사용자 동작이나 문서의 상태 변화 등을 감지하는 메커니즘입니다.
이벤트 리스너 추가
element.addEventListener('click', function(event) {
console.log('Element clicked!');
});
이벤트 리스너 제거
function handleClick(event) {
console.log('Clicked!');
}
element.addEventListener('click', handleClick);
// 나중에 제거
element.removeEventListener('click', handleClick);
주요 이벤트 타입
click
: 요소 클릭 시submit
: 폼 제출 시load
: 페이지나 이미지 로드 완료 시keydown
,keyup
: 키보드 키 누름/뗌mouseover
,mouseout
: 마우스 진입/이탈
이벤트 객체
이벤트 핸들러는 이벤트 객체를 받아 추가 정보를 얻을 수 있습니다.
element.addEventListener('click', function(event) {
console.log('Clicked at: ' + event.clientX + ', ' + event.clientY);
});
이벤트 전파
이벤트는 DOM 트리를 따라 전파됩니다.
- 캡처링 단계 : 최상위 요소에서 타겟 요소로
- 타겟 단계 : 이벤트가 타겟 요소에 도달
- 버블링 단계 : 타겟 요소에서 최상위 요소로
element.addEventListener('click', function(event) {
console.log('Captured!');
}, true); // 캡처링 단계에서 이벤트 감지
element.addEventListener('click', function(event) {
console.log('Bubbled!');
}); // 기본적으로 버블링 단계에서 이벤트 감지
이벤트 위임
부모 요소에 이벤트 리스너를 추가하여 자식 요소들의 이벤트를 효율적으로 처리할 수 있습니다.
document.getElementById('parent-list').addEventListener('click', function(e) {
if(e.target && e.target.nodeName == "LI") {
console.log("List item ", e.target.id, " was clicked!");
}
});
실제 예제 : 탭 인터페이스 구현
<div id="tab-container">
<div class="tab" data-tab="tab1">Tab 1</div>
<div class="tab" data-tab="tab2">Tab 2</div>
<div class="tab" data-tab="tab3">Tab 3</div>
</div>
<div id="content-container">
<div id="tab1" class="content">Content 1</div>
<div id="tab2" class="content">Content 2</div>
<div id="tab3" class="content">Content 3</div>
</div>
document.getElementById('tab-container').addEventListener('click', function(e) {
if(e.target && e.target.classList.contains('tab')) {
// 모든 탭과 콘텐츠 비활성화
document.querySelectorAll('.tab, .content').forEach(el => el.classList.remove('active'));
// 클릭된 탭과 해당 콘텐츠 활성화
e.target.classList.add('active');
document.getElementById(e.target.getAttribute('data-tab')).classList.add('active');
}
});
이 예제는 이벤트 위임을 사용하여 탭 인터페이스를 구현합니다.
각 탭을 클릭하면 해당 콘텐츠가 표시됩니다.
성능 고려사항
- DOM 조작 최소화 : DOM 조작은 비용이 많이 듭니다. 가능한 한 조작을 그룹화하고 최소화하세요.
- DocumentFragment 사용 : 여러 요소를 추가할 때는 DocumentFragment를 사용하여 한 번에 추가하세요.
let fragment = document.createDocumentFragment();
for(let i = 0; i < 1000; i++) {
let newElement = document.createElement('div');
fragment.appendChild(newElement);
}
document.body.appendChild(fragment);
- 이벤트 위임 활용 : 가능한 경우 개별 요소 대신 부모 요소에 이벤트 리스너를 추가하세요.
- 리플로우 최소화 : 스타일 변경이 리플로우를 트리거할 수 있습니다. 변경사항을 그룹화하고
requestAnimationFrame
을 사용하여 최적화하세요.
requestAnimationFrame(() => {
element.style.width = '100px';
element.style.height = '100px';
});
- 캐싱 : 자주 사용하는 DOM 요소는 변수에 저장하여 재사용하세요.
let myElement = document.getElementById('myElement');
// myElement를 반복해서 사용
DOM 조작과 이벤트 처리는 동적 웹 페이지 생성의 핵심입니다. 효과적인 DOM 조작을 통해 사용자 인터페이스를 동적으로 업데이트하고, 이벤트 처리를 통해 사용자 상호작용에 응답할 수 있습니다.
DOM API를 사용할 때는 성능에 주의를 기울여야 합니다. DOM 조작은 비용이 많이 드는 작업이므로, 필요한 경우에만 최소한으로 사용해야 합니다. 가능한 한 조작을 그룹화하고, DocumentFragment를 사용하여 여러 변경사항을 한 번에 적용하는 것이 좋습니다.
이벤트 처리에서는 이벤트 위임 기법을 활용하면 코드를 더 효율적으로 만들 수 있습니다. 특히 동적으로 생성되는 요소가 많은 경우에 유용합니다.
마지막으로, 현대 웹 개발에서는 React, Vue, Angular 같은 프레임워크를 사용하여 DOM 조작을 추상화하는 경우가 많습니다. 이러한 프레임워크들은 가상 DOM을 사용하여 성능을 최적화하고 개발자가 더 선언적인 방식으로 UI를 구현할 수 있게 해줍니다. 그러나 이러한 프레임워크의 기반에는 여전히 순수한 DOM 조작과 이벤트 처리 기술이 있으므로, 이에 대한 깊은 이해는 여전히 중요합니다.