[JavaScript] DOM

2023-09-18

DOM 기초


DOM은 Document Object Model의 약자로, HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model입니다. 즉, 여러분이 JavaScript를 사용할 수 있으면, DOM으로 HTML을 조작할 수 있습니다.

<script src="myScriptFile.js"></script>

웹 브라우저가 작성된 코드를 해석하는 과정에서 <script> 요소를 만나면, 웹 브라우저는 HTML 해석을 잠시 멈춥니다. HTML 해석을 잠시 멈춘 웹 브라우저는 <script> 요소를 먼저 실행합니다.

<script> 요소를 추가하는 두 가지 대표적인 사례가 존재합니다. 하나는 <head> 요소에 추가하는 방법, 다른 하나는 </body>가 끝나기 전에 추가하는 방법입니다. 두 사례를 비교해 보고 차이점은 무엇인지 알아봅시다

<head> 안쪽에 삽입하는 경우

230922-150251

<body> 요소가 끝나기 전에 삽입하는 경우

230922-150316

두 방식의 공통점과 차이점

두 방식 모두 myScriptFile.js 내의 첫 번째 console.log를 성공적으로 출력하지만,

두 번째 console.log의 경우 제대로 출력하지 못하는 예시가 있습니다.

// myScriptFile.js 파일
console.log('welcome JavaScript');
 
let msgElement = document.querySelector('#msg');
console.log(msgElement);

DOM 다루기


document 객체에는 많은 속성과 메서드가 존재합니다. 모든 속성과 메서드를 외워야 할까요? 지금 당장 전부 알아야 할 필요는 없습니다. 지금 집중할 부분은 CRUD(Create, Read, Update and Delete) 입니다. 앞으로 여러분이 앞으로 어떤 종류의 개발이나 컴퓨터 언어를 배우시더라도 가장 먼저 CRUD에 집중해야 합니다. CRUD를 먼저 이해하는 것이 새로운 언어를 가장 빠르게 학습하는 방법입니다.

CREATE

document.createElement('div');

위 코드는 div 태그를 생성합니다.

  • 새롭게 생성한 div element는 어떻게 활용할 수 있나요?

DOM을 끝까지 학습하면자바스크립트로 DOM을 조작할 수 있어야 합니다. 자바스크립트에서 어떤 작업의 결과를 담으려면 어떻게 해야 할까요?

변수를 선언하고 어떤 작업의 결과를 변수에 할당합니다. 여기서는 div element를 변수 tweetDiv에 할당합니다.

const tweetDiv = document.createElement('div');
  • 화면에 어떤 변화도 일어나지 않습니다. 제가 무엇을 놓쳤나요?

아직 화면에 변화가 없는 게 당연합니다. tweetDiv라는 요소는 현재 공중부양 중입니다. 다음 그림을 보며 설명합니다. DOM의 구조를 나타내는 트리 구조를 하나 그립니다. 아무것도 연결이 되어있지 않은 하나의 노드를 그립니다.

230922-150336

위 그림처럼 공중에 떠있는 엘리먼트를 확인하기 위해서는 APPEND 해야 합니다. APPEND 를 이용해 실제 웹 페이지 상에도 보이는 것을 확인할 수 있습니다. 이어지는 APPEND 부분에서, tweetDiv를 트리 구조에 연결합니다.

APPEND

CREATE에서 만든 tweetDiv라는 변수는 아직 "공중부양"을 하고 있습니다. 이번 콘텐츠에서는 append라는 메서드를 사용해서, 변수 tweetDiv<body>에 넣어보겠습니다.

document.body.append(tweetDiv);
  • 아무것도 보이지 않는데, 잘못 입력한 건가요?

아니요, 잘 적용된 겁니다. 새롭게 생성한 <div> 요소에 아무런 내용을 입력하지 않아서 보이는 내용이 없을 뿐입니다. 크롬의 개발자 도구 Elements 탭에서 내용을 확인하세요.

  • 내용은 어떻게 넣나요?

다음에 나오는 UPDATE에서 좀 더 자세히 설명합니다. 이번 콘텐츠에서는 textContent라는 메서드를 활용하면 문자열을 입력할 수 있습니다.

READ

자바스크립트에서 원시 자료형인 변수의 값을 조회하기 위해서는, 변수의 이름으로 직접 조회할 수 있습니다. 참조 자료형인 배열은 index를, 객체는 key를 이용해 값을 조회할 수 있습니다. 그러나 DOM은 조금 특별한 방법을 사용해야 합니다. DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인할 수 있습니다. 셀렉터로는 HTML 요소("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용됩니다.

참고로 querySelector는 셀렉터를 조회한다는 의미를 가지고 있습니다. query의 의미가 "질문하다"라는 것을 알고 있다면 역할을 쉽게 유추하실 수 있습니다. 이 query라는 단어는 개발자 간에 "ㅇㅇㅇ를 조회한다"라는 의미를 "쿼리를 날리다"라는 jargon(특정 영역에서만 사용되는 단어)로 굳어졌기 때문에 알고 있어야 합니다.

querySelector'.tweet'을 첫 번째 인자로 넣으면, 클래스 이름이 tweet인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회할 수 있습니다.

const oneTweet = document.querySelector('.tweet');

HTML 문서에는 클래스 이름이 tweet 인 요소가 여러 개 있는 데, 변수 oneTweet에 할당된 요소는 단 하나입니다. 여러 개의 요소를 한 번에 가져오기 위해서는, querySelectorAll을 사용합니다. 이렇게 조회한 HTML 요소들은 배열처럼 사용할 수 있습니다. 하지만 배열이 아닌 유사 배열 객체이니 주의하시기 바랍니다. (Array-like Object)

const tweets = document.querySelector('.tweet');

querySelectorquerySelectorAll만 알아도 대부분의 요소를 조회할 수 있습니다.

만약 이전 버전의 브라우저(인터넷 익스플로러) 호환성을 신경 써야 한다면, 이런 옛날 방식을 사용해야 할 수도 있습니다. 실제 동작은 동일하니 이런 메서드가 있다는 것 정도는 알아두세요.

const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true

CREATE에서 생성한 div 요소를 container에 넣을 준비를 마쳤습니다. 다음 코드를 입력하면, container의 맨 마지막 자식 요소로 tweetDiv를 추가합니다.

const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)

230922-150359

230922-150416

UPDATE

이번 콘텐츠 UPDATE에서는 기존에 생성한 빈 div 태그를 업데이트하여, 보다 다양한 작업을 할 수 있습니다. 먼저, textContent를 사용해서, 비어있는 div 엘리먼트에 문자열을 입력합니다.

const oneDiv = document.createElement('div');
console.log(oneDiv) // <div></div>
 
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>

앞서 생성한 div 엘리먼트를 container에 append 했을 때, CSS 스타일링이 적용되지 않았습니다. CSS 스타일링이 적용될 수 있도록, div 엘리먼트에 class를 추가합니다.

oneDiv.classList.add('tweet')
console.log(oneDiv) // <div class="tweet">dev</div>

생성한 엘리먼트에 텍스트를 채웠고, 클래스를 추가하여 스타일링을 적용했습니다. 이번에는 append를 이용해 container의 자식 요소로 추가합니다.

const container = document.querySelector('#container')
container.append(oneDiv)

230922-150442

DELETE

CRUD의 Delete, 삭제하는 법을 학습합니다. 삭제하는 방법에도 여러 가지가 있습니다. 먼저 삭제하려는 요소의 위치를 알고 있는 경우에 사용하는 방법입니다. 앞서 생성하고 추가한 tweetDiv를 삭제합니다. remove 메서드를 사용하세요.

const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // 이렇게 append 했던 요소를 삭제할 수 있다.

230922-150501

여러 개의 자식 요소를 지우려면, 어떻게 해야 할까요? innerHTML을 이용하면, 아주 간단하게 모든 자식 요소를 지울 수 있습니다. 컨테이너의 모든 자식 요소를 지우려면, 다음과 같이 입력합니다.

**document.querySelector('#container').innerHTML = '';**

innerHTML을 이용하는 방법은 분명 간편하고 편리한 방식이지만, innerHTML은 보안에서 몇 가지 문제를 가지고 있습니다. 이 방법을 대신할 다른 메서드를 사용합니다. removeChild는 자식 요소를 지정해서 삭제하는 메서드입니다. 모든 자식 요소를 삭제하기 위해, 반복문(while, for, etc.)을 활용할 수 있습니다. 다음의 코드는 자식 요소가 남아있지 않을 때까지, 첫 번째 자식 요소를 삭제하는 코드입니다.

const container = document.querySelector('#container');
while (container.firstChild) {
  container.removeChild(container.firstChild);
}

또는 직접 클래스 이름이 tweet인 요소만 찾아서 지우는 방법도 있습니다.

const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
    tweet.remove();
})
// or
for (let tweet of tweets){
    tweet.remove()
}

230922-150517

javascriptdom

프로필 사진
TaeWoo Kim
Junior Frontend Engineer