본문 바로가기
Development/WEB

DOM(Document Object Model)

by raphael3 2022. 11. 29.
반응형

DOM은 웹 문서 제어를 위한 프로그래밍 인터페이스다.
웹 상의 문서 내용과 문서의 구조를 구성하는 항목들(div, span, input 등)은 모두 object들이다. DOM은 이를 메모리에 계층으로 표현하며(그림 1) 이들을 제어(생성, 변형, 삭제 등)할 수 있도록 돕는 프로그래밍 인터페이스다. 이를 위해 API가 제공되며, 이들 API들은 브라우저에 이미 저장된 기능들이다. 따라서 DOM을 이용하면 웹 문서의 구조나 스타일, 내용을 바꿀 수 있다. 
DOM 자체는 프로그래밍 언어가 아니기 때문에 DOM을 이용하기 위해서는 주로 javascript와 같은 스크립트 언어를 이용한다.

그림 1. 브라우저는 HTML 문서를 읽을 때, 마치 나무와 같이 각 태그 요소들을 재조립하여 DOM 트리를 구성한다. 따라서 웹 페이지는 가장 상위의 <html> 태그부터 시작하여 계층 관계를 이룬다.

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);

result of querySelector, querySelectorAll

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.');
});

result of addEventListener after querySelector

위 결과는 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}`);
    })
});

result of addEventListener after querySelector & querySelectorAll

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);
    })
});

result of 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);
        item.textContent = `textContent ${index}`;
        console.log(`divElems- textContent: ${item.textContent}`);
        console.log(`divElems:`, item);
    })
});

result of textContent

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);
    })
});

result of classList.add

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}`));
    })
});

result of classList.contains

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);
    });
});

result of classList.remove

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);

result of getElementById, createElement, appendChild

지금까지 살펴본 것과 같이 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

 

문서 객체 모델 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 문서 객체 모델(영어: Document Object Model 도큐먼트 오브젝트 모델[*], DOM)은 XML, HTML 문서의 각 항목을 계층으로 표현하여 생성, 변형, 삭제할 수 있도록 돕는 인터

ko.wikipedia.org

 

Introduction to the DOM - Web APIs | MDN

The Document Object Model (DOM) is the data representation of the objects that comprise the structure and content of a document on the web. This guide will introduce the DOM, look at how the DOM represents an HTML document in memory and how to use APIs to

developer.mozilla.org

 

- https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById

 

Document.getElementById() - Web APIs | MDN

The Document method getElementById() returns an Element object representing the element whose id property matches the specified string. Since element IDs are required to be unique if specified, they're a useful way to get access to a specific element quick

developer.mozilla.org

- https://developer.mozilla.org/ko/docs/Web/API/Document/createElement

 

Document.createElement() - Web API | MDN

HTML 문서에서, Document.createElement() 메서드는 지정한 tagName의 HTML 요소를 만들어 반환합니다. tagName을 인식할 수 없으면 HTMLUnknownElement (en-US)를 대신 반환합니다.

developer.mozilla.org

- https://developer.mozilla.org/ko/docs/Web/API/Node/appendChild

 

Node.appendChild() - Web API | MDN

Node.appendChild() 메소드는 한 노드를 특정 부모 노드의 자식 노드 리스트 중 마지막 자식으로 붙입니다. 만약 주어진 노드가 이미 문서에 존재하는 노드를 참조하고 있다면 appendChild() 메소드는 노

developer.mozilla.org

 

반응형