이 문서는 웹 개발에서 자주 사용되는 자바스크립트 DOM(문서 객체 모델) 및 이벤트 조작의 핵심 개념들을 다양한 예제를 통해 설명합니다. 각 예제는 특정 기능을 구현하는 방법을 보여주며, 실제 웹 페이지 개발에 응용할 수 있는 실용적인 팁을 제공합니다.
1. 자식 요소 접근하기
DOM 트리에서 특정 요소의 자식 요소들에 접근하는 방법을 알아봅니다. children 속성을 사용하면 요소 노드인 자식들만 선택할 수 있습니다. 이는 텍스트 노드나 주석 노드까지 포함하는 childNodes와는 다릅니다.
<!DOCTYPE html>
<html>
<head>
<title>자식 요소 탐색</title>
</head>
<script type="text/javascript">
window.onload = function() {
const targetList = document.getElementById('myElementList');
// children 컬렉션은 요소 노드만 포함합니다.
for (let i = 0; i < targetList.children.length; i++) {
targetList.children[i].style.backgroundColor = 'lightcoral';
targetList.children[i].textContent = `아이템 ${i + 1} (색상 변경됨)`;
}
// 참고: childNodes는 텍스트 노드(공백 포함)까지 포함합니다.
// console.log('childNodes length:', targetList.childNodes.length);
// console.log('children length:', targetList.children.length);
};
</script>
<body>
<ul id="myElementList">
<li>아이템 1</li>
<li>아이템 2</li>
<li>아이템 3</li>
</ul>
</body>
</html>
2. 부모 요소 참조하기
특정 요소의 부모 요소에 접근해야 할 때 parentElement 속성을 사용할 수 있습니다. 이 예제에서는 목록 항목 내의 링크를 클릭했을 때 해당 목록 항목(부모 요소)을 DOM에서 제거합니다.
<!DOCTYPE html>
<html>
<head>
<title>부모 요소 조작</title>
<script type="text/javascript">
window.onload = function() {
const deleteButtons = document.querySelectorAll('#itemContainer li a.delete-link');
deleteButtons.forEach(button => {
button.addEventListener('click', function(event) {
event.preventDefault(); // 기본 링크 동작 방지
// 클릭된 링크의 부모 요소 (li)를 DOM에서 제거
this.parentElement.remove();
console.log('항목이 제거되었습니다.');
});
});
};
</script>
<style>
.delete-link { color: blue; cursor: pointer; text-decoration: underline; margin-left: 10px; }
</style>
</head>
<body>
<ul id="itemContainer">
<li>첫 번째 항목 <a href="#" class="delete-link">삭제</a></li>
<li>두 번째 항목 <a href="#" class="delete-link">삭제</a></li>
<li>세 번째 항목 <a href="#" class="delete-link">삭제</a></li>
<li>네 번째 항목 <a href="#" class="delete-link">삭제</a></li>
</ul>
</body>
</html>
3. 클래스 이름으로 요소 선택 및 스타일 적용
특정 클래스 이름을 가진 요소들을 선택하고 스타일을 적용하는 예제입니다. document.getElementsByClassName 또는 document.querySelectorAll을 사용하여 효율적으로 요소를 찾을 수 있습니다.
<!DOCTYPE html>
<html>
<head>
<title>클래스 이름으로 선택</title>
<style>
.highlight { border: 2px solid orange; }
</style>
</head>
<script type="text/javascript">
window.onload = function() {
const itemContainer = document.getElementById('classListExample');
// 'highlight' 클래스를 가진 모든 li 요소를 선택합니다.
const highlightedItems = itemContainer.getElementsByClassName('highlight');
// 선택된 각 요소에 배경색을 적용합니다.
for (let i = 0; i < highlightedItems.length; i++) {
highlightedItems[i].style.backgroundColor = 'lemonchiffon';
highlightedItems[i].textContent += ' (하이라이트됨)';
}
};
</script>
<body>
<ul id="classListExample">
<li>일반 아이템</li>
<li class="highlight">강조 아이템 A</li>
<li>다른 아이템</li>
<li class="highlight">강조 아이템 B</li>
<li>마지막 아이템</li>
</ul>
</body>
</html>
4. DOM 요소 제거하기
DOM에서 특정 요소를 제거하는 방법입니다. 이전 예제에서 사용했던 element.remove() 메서드는 부모 노드 없이 자기 자신을 제거할 수 있는 현대적인 방법입니다. 또는 parentNode.removeChild(childElement)를 사용할 수도 있습니다.
<!DOCTYPE html>
<html>
<head>
<title>요소 제거</title>
</head>
<script type="text/javascript">
window.onload = function() {
const removeItemButtons = document.querySelectorAll('#removableList li button');
removeItemButtons.forEach(button => {
button.addEventListener('click', function() {
// 버튼의 부모 요소 (li)를 제거합니다.
this.parentElement.remove();
console.log('리스트 항목이 완전히 제거되었습니다.');
});
});
};
</script>
<body>
<ul id="removableList">
<li>첫 번째 항목 <button>삭제</button></li>
<li>두 번째 항목 <button>삭제</button></li>
<li>세 번째 항목 <button>삭제</button></li>
<li>네 번째 항목 <button>삭제</button></li>
</ul>
</body>
</html>
5. 요소의 CSS 스타일 조회 및 설정 유틸리티
요소의 계산된 CSS 스타일을 안전하게 가져오고, 스타일을 설정하는 유틸리티 함수를 만드는 예제입니다. getComputedStyle은 현재 적용된 모든 CSS 속성 값을 반환하며, element.style은 인라인 스타일만 조작합니다.
<!DOCTYPE html>
<html>
<head>
<title>CSS 스타일 제어 함수</title>
<style type="text/css">
#styledBox { width: 150px; height: 150px; background-color: purple; margin: 20px; transition: background-color 0.3s ease; }
</style>
<script type="text/javascript">
/**
* 요소의 계산된 스타일을 가져오거나 스타일을 설정합니다.
* @param {HTMLElement} element - 대상 DOM 요소.
* @param {string} property - CSS 속성 이름 (camelCase).
* @param {string} [value] - 설정할 속성 값 (선택 사항).
* @returns {string|undefined} - 속성 값 조회 시 해당 값, 설정 시 undefined.
*/
function handleElementStyle(element, property, value) {
// 속성 값 설정
if (value !== undefined) {
element.style[property] = value;
return;
}
// 속성 값 조회
if (window.getComputedStyle) {
return getComputedStyle(element, null)[property];
} else if (element.currentStyle) { // IE 하위 버전 호환
return element.currentStyle[property];
}
return null;
}
window.onload = function() {
const toggleStyleButton = document.getElementById('controlButton');
const targetDiv = document.getElementById('styledBox');
toggleStyleButton.onclick = function() {
// 배경색을 변경하고 너비 값을 가져와 표시합니다.
const currentBg = handleElementStyle(targetDiv, 'backgroundColor');
if (currentBg === 'rgb(128, 0, 128)') { // purple
handleElementStyle(targetDiv, 'backgroundColor', 'darkgreen');
} else {
handleElementStyle(targetDiv, 'backgroundColor', 'purple');
}
alert('현재 박스의 너비: ' + handleElementStyle(targetDiv, 'width'));
};
};
</script>
</head>
<body>
<button id="controlButton">스타일 변경 및 확인</button>
<div id="styledBox"></div>
</body>
</html>
6. DOM 요소 동적으로 생성 및 삽입
사용자 입력에 따라 새로운 DOM 요소를 생성하고 기존 목록에 추가하는 예제입니다. document.createElement로 요소를 생성하고, appendChild로 마지막에 추가하거나, prepend (또는 insertBefore)로 맨 앞에 추가할 수 있습니다.
<!DOCTYPE html>
<html>
<head>
<title>DOM 요소 동적 생성</title>
</head>
<script type="text/javascript">
window.onload = function() {
const addButton = document.getElementById('addNewItemButton');
const dynamicList = document.getElementById('dynamicList');
const itemTextInput = document.getElementById('itemTextInput');
addButton.onclick = function() {
const newItemText = itemTextInput.value.trim();
if (newItemText === '') {
alert('내용을 입력해주세요.');
return;
}
const newListItem = document.createElement('li');
newListItem.textContent = newItemText; // 텍스트 콘텐츠 설정
// 새 항목을 목록의 맨 앞에 추가합니다.
dynamicList.prepend(newListItem);
itemTextInput.value = ''; // 입력 필드 초기화
itemTextInput.focus(); // 입력 필드에 포커스
};
};
</script>
<body>
<input type="text" id="itemTextInput" placeholder="새 항목 입력">
<button id="addNewItemButton">항목 추가</button>
<ul id="dynamicList"></ul>
</body>
</html>
7. 자바스크립트 객체(JSON 유사 구조) 활용
자바스크립트에서 객체 리터럴(JSON과 유사한 형태)을 선언하고 속성에 접근하며 반복하는 방법을 보여줍니다. for...in 루프는 객체의 열거 가능한 속성을 순회하는 데 유용합니다.
<!DOCTYPE html>
<html>
<head>
<title>객체 구조 및 순회</title>
</head>
<script type="text/javascript">
const userProfile = {
id: 101,
name: '김개발',
email: 'dev.kim@example.com',
hobbies: ['코딩', '독서', '운동'],
address: {
city: '서울',
zip: '01234'
}
};
console.log('사용자 이름:', userProfile.name);
console.log('첫 번째 취미:', userProfile.hobbies[0]);
console.log('주소 도시:', userProfile.address.city);
console.log('\n--- 사용자 프로필 정보 ---');
for (const key in userProfile) {
// 객체 자신의 속성만 처리 (프로토타입 체인에 있는 속성 제외)
if (userProfile.hasOwnProperty(key)) {
console.log(`${key}: ${userProfile[key]}`);
}
}
// 배열 객체 예시
const employeeData = [
{ empId: 'E001', name: '이하나', dept: '개발' },
{ empId: 'E002', name: '박두리', dept: '디자인' }
];
console.log('\n--- 직원 데이터 ---');
employeeData.forEach(employee => {
console.log(`직원 ID: ${employee.empId}, 이름: ${employee.name}`);
});
</script>
<body>
<p>콘솔을 확인하여 자바스크립트 객체 및 배열 데이터를 확인하세요.</p>
</body>
</html>
8. 키보드 이벤트 처리
키보드 입력을 감지하고 특정 키 조합에 반응하는 방법을 학습합니다. keydown 이벤트와 event.key 또는 event.keyCode를 사용하여 다양한 인터랙션을 구현할 수 있습니다.
8.1. 숫자만 입력 가능한 텍스트 필드
사용자가 숫자 외의 문자를 입력하지 못하도록 제한하는 예제입니다. event.key 속성을 활용하여 입력된 키를 확인합니다.
<!DOCTYPE html>
<html>
<head>
<title>숫자 전용 입력 필드</title>
</head>
<script type="text/javascript">
window.onload = function() {
const numberInput = document.getElementById('numericInput');
numberInput.addEventListener('keydown', function(event) {
const key = event.key;
// 숫자가 아니거나 (0-9) 제어 키가 아닌 경우 입력 방지
// (백스페이스, 탭, 화살표, Delete, Enter 등)
if (!(/[0-9]/.test(key) ||
key === 'Backspace' ||
key === 'Tab' ||
key === 'ArrowLeft' ||
key === 'ArrowRight' ||
key === 'Delete' ||
key === 'Home' ||
key === 'End')) {
event.preventDefault(); // 기본 이벤트 동작을 막음
}
});
};
</script>
<body>
<label for="numericInput">숫자만 입력:</label>
<input type="text" id="numericInput" placeholder="숫자를 입력하세요">
</body>
</html>
8.2. 키보드로 DIV 요소 움직이기
화살표 키를 사용하여 화면상의 div 요소를 움직이는 예제입니다. document.onkeydown을 사용하여 전역 키 이벤트를 처리하고 event.keyCode로 어떤 키가 눌렸는지 확인합니다.
<!DOCTYPE html>
<html>
<head>
<title>키보드 DIV 제어</title>
<style type="text/css">
#movableBlock { width: 80px; height: 80px; background-color: #4CAF50; position: absolute; top: 50px; left: 50px; }
</style>
<script type="text/javascript">
document.addEventListener('keydown', function(event) {
const movableDiv = document.getElementById('movableBlock');
const step = 15; // 이동 거리
switch (event.keyCode) {
case 37: // 왼쪽 화살표
movableDiv.style.left = (movableDiv.offsetLeft - step) + 'px';
break;
case 39: // 오른쪽 화살표
movableDiv.style.left = (movableDiv.offsetLeft + step) + 'px';
break;
case 38: // 위쪽 화살표
movableDiv.style.top = (movableDiv.offsetTop - step) + 'px';
break;
case 40: // 아래쪽 화살표
movableDiv.style.top = (movableDiv.offsetTop + step) + 'px';
break;
}
event.preventDefault(); // 스크롤 등 기본 동작 방지
});
</script>
</head>
<body>
<div id="movableBlock"></div>
<p style="margin-top: 200px;">화살표 키로 녹색 블록을 움직여보세요.</p>
</body>
</html>
8.3. Ctrl + Enter로 메시지 전송
텍스트 영역에서 Ctrl 키와 Enter 키를 동시에 눌러 메시지를 전송하는 기능을 구현합니다. event.ctrlKey와 event.key를 함께 사용합니다.
<!DOCTYPE html>
<html>
<head>
<title>Ctrl+Enter 메시지 전송</title>
</head>
<script type="text/javascript">
window.onload = function() {
const sendButton = document.getElementById('sendMessageButton');
const messageHistoryArea = document.getElementById('messageHistory');
const newMessageInput = document.getElementById('newMessageInput');
// 버튼 클릭 시 메시지 전송
sendButton.onclick = function() {
const message = newMessageInput.value.trim();
if (message === '') return;
messageHistoryArea.value += message + '\n';
newMessageInput.value = '';
newMessageInput.focus();
};
// Ctrl + Enter 키 조합으로 메시지 전송
newMessageInput.onkeydown = function(event) {
if (event.ctrlKey && event.key === 'Enter') {
sendButton.click(); // 버튼 클릭 이벤트 발생
event.preventDefault(); // Enter 키로 인한 줄바꿈 방지
}
};
};
</script>
<body>
<h3>메시지 기록</h3>
<textarea id="messageHistory" rows="10" cols="50" readonly></textarea><br/>
<input type="text" id="newMessageInput" placeholder="메시지를 입력하고 Ctrl+Enter">
<button id="sendMessageButton">전송</button>
</body>
</html>
9. 스크롤 위치 및 사용자 정의 컨텍스트 메뉴
window.scrollTop을 활용하여 요소를 화면에 고정시키거나, 사용자 정의 마우스 우클릭 메뉴를 구현하는 예제입니다.
9.1. 스크롤 시 화면 중앙에 고정되는 요소
페이지 스크롤에 따라 항상 화면 중앙에 위치하는 요소를 만듭니다. document.documentElement.scrollTop (또는 document.body.scrollTop)을 이용하여 현재 스크롤 위치를 파악하고 요소의 top 위치를 동적으로 조정합니다. 현대 CSS의 position: fixed와 top: 50%; transform: translateY(-50%);를 사용하면 더 간편하게 구현할 수 있지만, 여기서는 스크롤 이벤트를 통한 JS 제어를 보여줍니다.
<!DOCTYPE html>
<html>
<head>
<title>스크롤 고정 요소</title>
<style type="text/css">
body { height: 2500px; margin: 0; padding: 0; font-family: sans-serif; }
#floatingElement {
width: 120px;
height: 120px;
background-color: darkblue;
color: white;
text-align: center;
line-height: 120px;
position: absolute; /* JS로 top을 제어할 것이므로 absolute */
right: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
font-size: 0.9em;
}
</style>
<script type="text/javascript">
window.addEventListener('scroll', updateFloatingElementPosition);
window.addEventListener('resize', updateFloatingElementPosition);
window.addEventListener('load', updateFloatingElementPosition);
function updateFloatingElementPosition() {
const targetElement = document.getElementById('floatingElement');
const scrollY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
const viewportHeight = document.documentElement.clientHeight;
const elementHeight = targetElement.offsetHeight;
// 뷰포트 중앙에 오도록 계산
const newTop = scrollY + (viewportHeight - elementHeight) / 2;
targetElement.style.top = newTop + 'px';
}
</script>
</head>
<body>
<h1 style="padding-left: 20px;">페이지를 아래로 스크롤해보세요</h1>
<div id="floatingElement">항상 중앙에!</div>
<p style="margin-top: 1500px; padding-left: 20px;">페이지 하단 내용</p>
</body>
</html>
9.2. 사용자 정의 마우스 우클릭 메뉴 구현
브라우저의 기본 컨텍스트 메뉴 대신 사용자 정의 메뉴를 표시하는 예제입니다. contextmenu 이벤트를 가로채어 기본 동작을 막고, 마우스 클릭 위치에 메뉴를 배치합니다. event.clientX, event.clientY를 사용하여 마우스 포인터의 위치를 가져옵니다.
<!DOCTYPE html>
<html>
<head>
<title>사용자 정의 컨텍스트 메뉴</title>
<style type="text/css">
body { margin: 0; padding: 0; font-family: sans-serif; height: 1200px; } /* 스크롤바를 위해 높이 추가 */
#customContextMenu {
width: 150px;
background-color: #fff;
border: 1px solid #ddd;
box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
position: absolute;
display: none; /* 초기에는 숨김 */
z-index: 1000;
list-style: none;
padding: 5px 0;
border-radius: 4px;
}
#customContextMenu li {
padding: 8px 15px;
cursor: pointer;
font-size: 0.9em;
}
#customContextMenu li:hover {
background-color: #f0f0f0;
}
.info-area {
margin: 50px;
padding: 20px;
border: 1px dashed #ccc;
height: 200px;
text-align: center;
line-height: 200px;
background-color: #f9f9f9;
}
</style>
<script type="text/javascript">
document.addEventListener('contextmenu', function(event) {
event.preventDefault(); // 브라우저 기본 컨텍스트 메뉴 비활성화
const menuElement = document.getElementById('customContextMenu');
// 현재 스크롤 위치를 고려하여 메뉴 위치 설정
const scrollX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
const scrollY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
menuElement.style.left = (event.clientX + scrollX) + 'px';
menuElement.style.top = (event.clientY + scrollY) + 'px';
menuElement.style.display = 'block'; // 메뉴 표시
});
// 문서 어디든 클릭하면 메뉴 숨김
document.addEventListener('click', function() {
const menuElement = document.getElementById('customContextMenu');
menuElement.style.display = 'none';
});
// 메뉴 항목 클릭 시 동작 정의
document.getElementById('customContextMenu').addEventListener('click', function(event) {
const clickedItem = event.target.textContent;
alert(`"${clickedItem}" 항목이 선택되었습니다.`);
// 이후 여기에 실제 동작을 추가할 수 있습니다.
});
</script>
</head>
<body>
<div class="info-area">이 영역에서 마우스 오른쪽 버튼을 클릭해보세요!</div>
<ul id="customContextMenu">
<li>새로고침</li>
<li>다른 이름으로 저장</li>
<li>요소 검사</li>
<li>닫기</li>
</ul>
</body>
</html>