DOM은 웹 문서 제어를 위한 프로그래밍 인터페이스다.
웹 상의 문서 내용과 문서의 구조를 구성하는 항목들(div, span, input 등)은 모두 object들이다. DOM은 이를 메모리에 계층으로 표현하며(그림 1) 이들을 제어(생성, 변형, 삭제 등)할 수 있도록 돕는 프로그래밍 인터페이스다. 이를 위해 API가 제공되며, 이들 API들은 브라우저에 이미 저장된 기능들이다. 따라서 DOM을 이용하면 웹 문서의 구조나 스타일, 내용을 바꿀 수 있다.
DOM 자체는 프로그래밍 언어가 아니기 때문에 DOM을 이용하기 위해서는 주로 javascript와 같은 스크립트 언어를 이용한다.
DOM API에는 기본적으로 다음의 것들이 있다.
- querySelector
- querySelectorAll
- addEventListener
- classList.add
- classList.contains
- classList.remove
- textContent
- getElementById
- createElement
- appendChild
querySelector
가장 먼저 찾은 HTML 요소 하나만 반환한다.
querySelectorAll
찾아낸 모든 HTML 요소를 반환한다. -> 유사 배열이 된다.
이들 querySelector와 querySelectorAll은 깊이 우선 탐색(DFS)을 이용하여 특정 요소를 찾아낸다. querySelector의 경우 요소를 찾아내면 곧바로 종료되고, querySelectorAll의 경우 모든 노드를 방문할 것이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/main.css" />
<script defer src="./js/main.js"></script>
</head>
<body>
<div class="div">div element 1</div>
<div class="div">div element 2</div>
<div class="div">div element 3</div>
<div class="div">div element 4</div>
<div class="div">div element 5</div>
</body>
</html>
const divElem = document.querySelector('.div');
console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
console.log('querySelectorAll result: ', divElems);
addEventListener
addEventListener는 querySelector나 querySelectorAll 등으로 찾은 요소에 대하여 특정 이벤트가 발생하는지 감시하고, 해당 이벤트가 발생하면 익명 함수(핸들러)를 실행시킨다.
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.addEventListener('click', function() {
console.log('divElems addEventListener Executed.');
});
위 결과는 querySelector로 찾은 요소에 대한 addEventListener의 결과로서, 이벤트는 click이고 핸들러로 실행하는 함수는 console 출력이다.
querySelectorAll도 적용했기 때문에 클릭했을 시에 두 개의 결과가 떠야 한다. 그러나 querySelectorAll로 찾은 요소에 대해서는 위와 같이 코드를 작성할 경우 클릭해도 핸들러가 작동하지 않는데, 그 이유는 querySelectorAll는 일련의 여러 요소들을 유사 배열로 반환하기 때문이다. 따라서 forEach를 이용하여 각 요소에 하나하나 접근해야 한다.
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.forEach(function(item, index) {
item.addEventListener('click', function() {
console.log(`divElems- item: ${item}, index: ${index}`);
})
});
div element 1을 클릭할 경우 querySelector에 대한 addEventListener가 실행된 결과와 querySelectorAll에 대한 addEventListener가 실행된 결과가 모두 보여지게 된다.
textContent
textContent는 특정 요소가 가지고 있는 텍스트를 반환할 수 있고, 값을 넣을 수도 있게 한다.
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.forEach(function(item, index) {
item.addEventListener('click', function() {
console.log(`divElems- textContent: ${item.textContent}`);
console.log(`divElems:`, item);
})
});
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.forEach(function(item, index) {
item.addEventListener('click', function() {
console.log(`divElems- textContent: ${item.textContent}`);
console.log(`divElems:`, item);
item.textContent = `textContent ${index}`;
console.log(`divElems- textContent: ${item.textContent}`);
console.log(`divElems:`, item);
})
});
textContent를 이용하면 특정 요소가 가진 텍스트를 반환받을 수도 있고, 초기화 할 수도 있다. 위 예시는 div element 1, 2까지를 클릭한 결과로서 텍스트 자체가 변경된 것을 확인할 수 있다.
classList
classList를 이용하면 특정 요소에 class를 추가, 삭제, 확인이 가능하다.
classList.add
classList.add는 class를 추가한다.
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.forEach(function(item, index) {
item.addEventListener('click', function() {
item.classList.add(`${index}`)
console.log(`divElems- textContent: ${item.textContent}, index: ${index}`);
console.log('divElems: ', item);
})
});
classList.contains
특정 클래스 요소가 있는지 검사한다.
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.forEach(function(item, index) {
item.addEventListener('click', function() {
item.classList.add(`${index}`)
console.log(`divElems- textContent: ${item.textContent}`);
console.log(`divElem:`, item);
console.log('classList.contains:', item.classList.contains(`${index}`));
})
});
classList.remove
classList.remove는 특정 요소가 가진 특정 클래스를 지운다.
const divElem = document.querySelector('.div');
// console.log('querySelector result: ', divElem);
const divElems = document.querySelectorAll('.div');
// console.log('querySelectorAll result: ', divElems);
divElem.addEventListener('click', function() {
console.log('divElem addEventListener Executed.');
});
divElems.forEach(function(item, index) {
item.classList.add(`${index}`);
console.log('divElems:', item);
});
divElems.forEach(function(item, index) {
item.addEventListener('click', function() {
item.classList.remove(`${index}`);
console.log('divElems: ', item);
});
});
getElementById
getElementById는 id 속성과 일치하는 HTML element를 찾아낸다. id는 element별로 유일하기 때문에 특정 element를 빠르게 지정할 수 있다.
createElement
createElement는 지정한 HTML element를 만들어 반환한다.
appendChild
DOM은 HTML element들을 노드로 하는 일종의 트리다. appendChild는 createElement로 만든 노드(element)를 자식 노드로 하여 특정 노드(parent)에 붙인다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/main.css" />
<script defer src="./js/main.js"></script>
</head>
<body>
<div id="div"></div>
</body>
</html>
const divElem = document.getElementById('div');
const elem = document.createElement('h1');
elem.textContent = 'RaphDohk';
divElem.appendChild(elem);
지금까지 살펴본 것과 같이 DOM을 직접 제어할 수 있지만, 페이지 리로딩 시간이 늘어날 수 있다. 그래서 가상 DOM 개념이 등장했고, 이 가상 DOM을 이용하여 리랜더링 시간을 줄이는 React가 등장했다.
가상 DOM은 일종의 복사본인데, 기존의 요소와 비교하여 변경된 요소들을 파악하여 이를 리랜더링하기 때문에 빠르다고 볼 수 있다.
- https://ko.wikipedia.org/wiki/%EB%AC%B8%EC%84%9C_%EA%B0%9D%EC%B2%B4_%EB%AA%A8%EB%8D%B8
- https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction
- https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
- https://developer.mozilla.org/ko/docs/Web/API/Document/createElement
- https://developer.mozilla.org/ko/docs/Web/API/Node/appendChild
'Development > WEB' 카테고리의 다른 글
이미지 렌더링 & Raster와 Vector (0) | 2022.12.01 |
---|---|
서버, 클라이언트, 프로토콜, 통신, 웹 표준 (0) | 2022.11.30 |
[FastCampus] '프로그래밍 첫걸음 시작하기' 강의 노트 (0) | 2019.08.29 |