Document Object Model 의 약어로 웹 문서를 제어하기 위해서 웹 문서를 객체화한 것을 말한다.
여기서 의미하는 객체는 값을 나타내는 프로퍼티와 어떠한 수행을 하는 메서드를 갖고 있다.
이렇게 웹 문서(HTML)를 객체화 함으로써 우리는 객체로 웹 문서를 제어할 수 있게 된다.
HTML 요소를 선택하기 위해서는 GET 메서드를 사용해야 한다
get 메서드
document.getElementById - 모든 HTML 요소에는 고유한 ID를 할당받을 수 있다document.getElementsByClassName - HTML 클래스 명으로 요소를 찾을 수 있다.document.getElementsByTagName - HTML 태그명으로 요소를 찾을 수 있다.<ul id="list">
<li class="item">
<li class="item">
<li class="item">
</ul>
라는 코드가 있다고 가정해보자
document.getElementById('list')
document.getElementsByClassName('item')
document.getElementsByTagName('li')
순서대로 id 인 list를 선택하기, class 이름인 item을 선택하기, <>태그 이름인 li를 선택할 수 있다.
DOM 요소 쿼리
get 메서드와 같은 방법도 유용하지만, ID나 클래스, 태그 이름 같은 한 가지 조건이 아니라 다른 요소와의 관계를 사용해 원하는 요소를 찾는 훨씬 더 강력하고 범용적인 메서드도 있다.
querySelector와 querySelectorAll은 CSS 선택자를 사용해 요소를 찾는 메서드이다.
document.querySelector(CSS Selector) - 지정된 선택자에 일치하는 문서 내 첫 번째 요소를 반환한다. 일치하는 요소가 없으면 null을 반환한다.document.querySelectorAll - 지정된 선택자에 일치하는 요소 목록을 반환한다.콘텐츠 수정
textContent와 innerHTML 프로퍼티를 통해 요소의 콘텐츠를 가져오거나 수정할 수 있다.
textContent - HTML 태그를 모두 제거하고 순수한 텍스트 데이터만 제공한다.innerHTML - HTML 태그를 그대로 제공한다.이게 무슨 말일까?
이렇게 <span> 태그를 붙여서 innerHTML, textContent를 각각 출력해보자


첫번째 사진이 innerHTML 프로터피를 사용해서 출력한 결과이다.
--> innerHTML 의 경우, 태그 를 같이 추가하는 (변경하는) 겻을 확인할 수 있다.
--> 반면, textContent의 경우, 태그는 제외한 후, 텍스트만 변경한 것을 확인할 수 있다.
속성 제어하기
setAttribute - 요소에서 주어진 이름의 속성값을 입력한다.
html 태그에 placeholder = "운동을 입력해주세요"가 지정되어 있다. document.querySelector('input').setAttribute('placeholder', '오늘 할 운동은 ?');
태그를 추가하자,
로 변경된 것을 확인할 수 있다 :)
getAttribute - 요소에서 주어진 속성의 값을 가져온다.removeAttribute - 요소에서 주어진 이름의 속성을 제거한다.요소 프로퍼티 직접 수정
style - style 프로퍼티를 사용하여 직접 수정const btn = document.getElementById('button');
btn.style.color = 'white';
btn.style.backgroundColor = 'black';
CSS 클래스 이용
const btn = document.getElementById('button');
btn.classList.add('dark')
btn.classList.remove('dark')
.dark {
color: wheat;
background-color: black;
}
.light {
color: black;
background-color: wheat;
}
새로운 요소 만들기
createElement - 지정한 tagName의 HTML 요소를 생성한다.const element = document.createElement('p');
--> p태그를 생성하는 코드이다.
appendChild - 항상 마지막 자식 요소로 추가const li = document.createElement('li');
li.textContent = 'Hello';
document.querySelector('ul').appendChild(li);
--> 새로운 <li>요소를 생성하고, 해당 요소에 'Hello'라는 텍스트 콘텐츠를 추가한 후, 이를 문서에 있는 <ul> 요소의 자식으로 추가하는 것을 의미한다.
insertBefore - 추가할 곳 위치 앞에 추가한다const firstItem = document.querySelector('.first-item');
const li = document.createElement('li');
li.textContent = 'Hello';
document.querySelector('ul').insertBefore(li, firstItem);
--> 새로운 <li> 요소를 생성한 후, insertBefore 메서드로 자식 요소를 추가 --> "li를 firstItem 앞에 추가한다" 를 의미!
오늘의 운동을 추가할 수 있는 이런 페이지가 있다고 가정해보자.
1 . appendChild()
const li = document.createElement('li');
const ul = document.querySelector('.list');
const inputBox = document.querySelector('input');
const addBtn = document.querySelector('#button');
addBtn.addEventListener('click', () => {
li.textContent = inputBox.value;
ul.appendChild(li);
});
<li> 요소를 생성하고 이를 li 변수에 할당<ul> 요소를 찾아 ul 변수에 할당<input> 요소를 찾아 inputBox 변수에 할당<li>요소의 텍스트 콘텐츠로 설정한다.
const addBefore = document.querySelector('#before');
const targetLi = document.querySelector('#target');
addBefore.addEventListener('click', () => {
li.textContent = inputBox.value;
ul.insertBefore(li, targetLi);
});
<li> 요소의 텍스트 콘텐츠로 설정<li>요소를 targetLi 요소의 앞에 삽입

먼저, 스쿼트 옆에 버튼을 눌렀을 때, 스쿼트가 삭제되도록 코드를 작성해보자
const removeBtn = document.querySelector('.remove-btn');
removeBtn.addEventListener('click', () => {
const targetLi = document.querySelector('li#target');
targetLi.remove();
});

이제는 추가 버튼을 눌렀을 때, text 옆에 X 삭제 버튼이 같이 생기면서, 삭제 버튼을 눌렀을 때, 삭제할 수 있도록 코드를 한번 짜보자!
addBtn.addEventListener('click', () => {
const li = document.createElement('li');
li.textContent = inputBox.value;
// 새로운 삭제 버튼 생성
const button = document.createElement('button');
button.textContent = '❌';
// 삭제 버튼 이벤트 리스너 추가
button.addEventListener('click', (e) => {
e.target.parentNode.remove();
});
li.appendChild(button);
ul.appendChild(li);
});
빨간색 X 버튼이 생기고, x를 누를 때, 여러개 동시에 생기는 것을 확인할 수 있다!
간단하게 코드 해석해보고 넘어가자
여기서, parentNode를 사용하지 않고
button.addEventListener('click', () => {
li.remove();
});
로 실행해도 코드는 제대로 실행되는 것을 확인할 수 있다.
추가적인 기능
inputBox.value = ' ';
inputBox.focus();
텍스트 상자에 글자를 입력 후, 추가 버튼을 누르면, 입력 상자(inputBox)의 값을 비우고, 그 상자에 포커스를 맞추는 기능이다.

이러한 작은 기능들이 페이지를 작동할 때 더 쉽게 작동할 수 있도록 도움을 준다.
이건 처음 보는 속성이자 기능(?) 인 것 같다
HTML5에서는 데이터(data-) 속성을 도입했다.
이 속성을 사용해서 HTML 요소에 임의의 데이터를 추가할 수 있습니다.
--> 브라우저는 이 데이터 속성을 완전히 무시하므로 자바스크립트에서 쉽게 요소에 관한 정보를 읽거나 수정할 수 있다.
dataset
HTML 요소의 dataset 프로퍼티로 데이터(data-) 속성을 읽거나 수정할 수 있다.
예시로 알아보자

사과를 눌렀을 때, 사과 이미지가 나오고, '사과를 선택했습니다' 라는 문구가 나오도록 코드를 작성해보자
<body>
<h2>과일</h2>
<ul>
<li data-img="../img/apple.jpg">사과</li>
<li data-img="../img/tomatoes.jpg">토마토</li>
<li data-img="../img/blueberries.jpg">블루베리</li>
</ul>
<h2 class="selected-item">과일을 선택해주세요.</h2>
<img style="width: 200px" src="" alt="과일" />
</body>
우선 HTML을 살펴보면, img 태그에 이미지 위치를 저장하는 src 속성에 빈 값으로 저장해 두었다.
그리고 사과, 토마토, 블루베리에 각각 data-img 속성을 사용해 이미지 주소를 저장해 두었다.
const liList = document.querySelectorAll('li');
const img = document.querySelector('img');
const text = document.querySelector('.selected-item');
liList[0].addEventListener('click', (event) => {
img.setAttribute('src', event.target.dataset.img);
text.textContent = event.target.textContent + '를 선택했습니다.';
});
<li> 요소를 선택하고, 이를 liList라는 변수에 저장한다.<img>요소를 선택하고, 이를 img라는 변수에 저장한다.'selected-item'인 요소를 선택하고, 이를 text라는 변수에 저장한다.
사과를 선택하자, 이렇게 이미지와 텍스트가 정상적으로 출력하는 것을 확인할 수 있다.
그럼 나머지 토마토, 블루베리도 똑같은 코드를 설정해주어야 하는데, 그럼 스크립트 파일에 중복된 코드가 3개가 되는 것이다.
또한 다른 기능을 추가하고 싶을 때에도 3개 모두 추가를 해주어야 한다.
--> 이러한 중복과 가독성을 위해 반복적으로 사용하는 것들을 함수로 묶어서 사용하면 된다.
liList[0].addEventListener('click', selectItem);
liList[1].addEventListener('click', selectItem);
liList[2].addEventListener('click', selectItem);
function selectItem(event) {
img.setAttribute('src', event.target.dataset.img);
text.textContent = event.target.textContent + '를 선택했습니다.';
}
또한 여기서 또 잘 살펴보면
liList[0].addEventListener('click', selectItem);
liList[1].addEventListener('click', selectItem);
liList[2].addEventListener('click', selectItem);
이 부분이 중복적으로 사용되는 것을 확인할 수 있다. 이를 어떻게 해결하면 좋을 까?
document.querySelectorAll('li');를 사용하여<li>요소를 선택하면, NodeList 객체가 반환된다. 이는 배열과 유사하지만 완전한 배열은 아니다. NodeList는 실제 배열이 아니므로 배열의 메서드를 직접 사용할 수는 없다.
forEach() 메서드는 각 요소에 대해 주어진 함수를 한 번씩 실행한다. 이것은 반복 가능한(iterable) 객체에 대해 유용한 일반적인 반복 작업이다. 따라서 NodeList에서도forEach()메서드를 사용하여 각 요소에 대한 반복 작업을 수행할 수 있다!
liList.forEach((li) => {
li.addEventListener('click', selectItem);
});
--> liList.forEach()를 사용하여 각 요소에 대해 클릭 이벤트에 대한 이벤트 리스너를 추가하면 된다!
인라인 (Inline)
이벤트 대상의 HTML 태그 속성으로 지정, this를 통해 이벤트가 발생한 대상 요소를 참조할 수 있다.
<button onclick="alert('hello');">버튼</button>
프로퍼티 리스너 (Property Listener)
이벤트 대상이 되는 객체의 프로퍼티로 이벤트 등록
<button id="btn">버튼</button>
const btn = document.getElementById('btn')
btn.onclick = function () {
alert('hello');
}
AddEventListener()
이벤트를 등록하는 가장 권장되는 방식이며, 하나의 이벤드 대상 요소에 여러개의 이벤트를 등록할 수 있다.
btn2.addEventListener('click', () => {
alert('안녕 나는 addEventListener 이지롱 ');
});
이벤트 제거하기
removeEventListener - addEventListener 로 등록했던 이벤트를 제거한다.
위와 같이, removeEventListener()를 사용하려면, 함수로 정의되어 있어야 한다!쉽게 설명하자면, 이벤트 객체는 이벤트가 발생했을 때, 해당 이벤트에 대한 정보를 담고 있는 객체이다.
btn.addEventListener('click', function(event) {
console.log('event: ', event);
})
mousedown - 마우스가 요소안에서 클릭이 눌릴 때mouseup - 마우스가 요소안에서 클릭이 해제될 때mouseenter - 마우스 포인터가 요소 안으로 진입 했을 때mouseleave - 마우스 포인터가 요소 밖깥으로 나갔을 때mousemove - 마우스 포인터가 요소 안에서 움직일 때
.rectangle {
border: 1px solid black;
width: 300px;
height: 150px;
background-color: green;
}
.rectangle-red {
border: 1px solid black;
width: 300px;
height: 150px;
background-color: red;
}
rectangle.addEventListener('mousedown', (e) => {
rectangle.classList.add('rectangle-red');
});
rectangle.addEventListener('mouseup', (e) => {
rectangle.classList.remove('rectangle-red');
});
'mousedown' 이벤트에서는 'rectangle-red' 클래스를 추가하여 배경을 빨간색으로 변경하고, 'mouseup' 이벤트에서는 'rectangle' 클래스를 제거하고 기본적인 속성인 'rectangle'를 유지하도록 코드를 작성해 보았다.
원래 기본 상태
마우스를 눌렀을 때
요로코롬 이벤트가 적용된 것을 확인할 수 있다!
rectangle.addEventListener('mouseenter', () => {
rectangle.classList.add('rectangle-blue');
rectangle.classList.remove('rectangle-yellow');
});
rectangle.addEventListener('mouseleave', () => {
rectangle.classList.remove('rectangle-blue');
rectangle.classList.add('rectangle-yellow');
});
mouseenter 기능을 사용하면, 마우스가 상자 안에 들어가면, 파란색으로 변하고, 상자 밖으로 나오면 노란색으로 바뀌도록, 설정해 두었다.
이런식으로 마우스 이벤트를 적용하면 된다!
유용한 이벤트 속성&메서드
event.clientX event.clientY - 브라우저 화면 기준 X, Y 좌표event.pageX event.pageY - 전체화면 기준(스크롤 포함) X, Y좌표event.target.getBoundingClientRect() - 요소의 크기와 뷰포트로 부터 상대적인 위치를 반환rectangle.addEventListener('mousedown', (event) => {
console.log('clientX : ', event.clientX, 'clientY :', event.clientY);
console.log('pageX : ', event.pageX, 'pageY :', event.pageY);
});
이렇게 현재 내가 보고 있는 브라우저 화면 기준으로 X, Y 좌표를 출력하거나, 전체 화면의 기준의 X,Y의 값을 출력해보자

요렇게 출력되는 것을 확인할 수 있다.
그렇다면, X 와 Y 좌표를 활용해서 내가 클릭한 곳에 동그란 원을 화면에 띄어보도록 해보자
나는 화면 전체에 어디든지 동그란 원을 띄우기 위해 body 태그 전체를 가지고 온다.
const body = document.querySelector('body');
.circle {
height: 50px;
width: 50px;
background-color: red;
position: absolute;
border-radius: 50%;
/* left: 400px;
top: 100px; */
}
이후 css 속성으로 circle의 속성을 지정해 둔다.
body.addEventListener('click', (event) => {
const div = document.createElement('div');
div.classList.add('circle');
div.style.left = event.pageX - 25 + 'px';
div.style.top = event.pageY - 25 + 'px';
body.appendChild(div);
});
body.addEventListener('click', (event) => { ... }) : body 요소에 클릭 이벤트 리스너를 추가한다 즉, 페이지의 어느 곳이든 클릭이 발생하면 이벤트가 실행된다. const div = document.createElement('div'); : 새로운 div 요소를 생성한다.div.classList.add('circle'); : 새로 생성된 div 요소에 위에 정의한 'circle' 클래스를 추가한다.div.style.left = event.pageX - 25 + 'px';: 생성된 div 요소의 가로 위치를 설정한다. event.pageX는 클릭이 발생한 페이지의 X 좌표를 나타내며, 여기서 25를 빼는 이유는 원의 중심이 되는 위치로 설정하기 위해서이다. 'px'는 픽셀 단위를 나타낸다.div.style.top = event.pageY - 25 + 'px'; : 생성된 div 요소의 세로 위치를 설정한다. event.pageY는 클릭이 발생한 페이지의 Y 좌표를 나타내며, 마찬가지로 25를 빼는 이유는 원의 중심이 되는 위치로 설정하기 위해서이다. body.appendChild(div); : body 요소에 생성된 div 요소를 추가한다. 따라서 클릭할 때마다 새로운 div 요소가 생성되어 페이지에 추가된다.
이렇게 클릭한 위치에 원이 정 가운데로 설정되는 것을 확인할 수 있다!
keydown : 키보드의 키가 눌렸을 때 발생하는 이벤트keypress : 키보드의 문자 키가 입력되었을 때 발생하는 이벤트keyup : 키보드의 키가 눌렸다가 떼어졌을 때 발생하는 이벤트inputBox.addEventListener('keypress', (e) => {
console.log('keypress');
});
inputBox.addEventListener('keydown', (e) => {
console.log('keydown');
});
inputBox.addEventListener('keyup', (e) => {
console.log('e.key : ' + e.key);
console.log('e.keyCode : ' + e.keyCode);
});
이런식으로 코드를 작성할 수 있다.
여기서, e.key 는 키보드에 입력한 문구를 출력하는 것이고, e.keyCode 문자의 아스키코드 코드 값을 반환한다.
연습 코드
inputBox.addEventListener('keypress', (e) => {
// 키가 입력될 때마다 inputBox의 배경색을 노란색으로 변경
inputBox.style.backgroundColor = 'yellow';
});
inputBox.addEventListener('keyup', (e) => {
// 입력이 끝나면 inputBox의 배경색을 다시 원래대로 되돌림
inputBox.style.backgroundColor = '';
});
키보드의 키가 눌렸을 때, inputBox의 배경을 노란색으로 변경하고, 입력이 끝나는 즉시 다시 원래대로 되돌리는 코드이다.
글자가 입력될 때 칸이 노란색으로 변한 것이다!
focus : 요소가 포커스를 받았을 때 발생하는 이벤트blur: 요소가 포커스를 잃었을 때 발생하는 이벤트change : 입력 요소의 값이 변경될 때 발생하는 이벤트focus
inputBox.addEventListener('focus', () => {
alert('focus 성공');
});

inputBox에 포커스가 발생했을 때, 알림창을 뜰 수 있도록 코드를 작성해 보았다.
그럼 포커스에서 벗어날 때는 어떻게 작성하면 될까?
blur
inputBox.addEventListener('blur', () => {
alert('blur 실행');
});

change
inputBox.addEventListener('change', () => {
console.log('입력값 변경');
});
입력 값이 변할 때마다, 콘솔에 '입력값 변경'을 띄우도록 코드를 작성해 보았다.

submit - 양식(Form)이 제출하기전에 발생 하는 이벤트 입니다. 주로 전송될 값을 유효성 체크할 때 사용한다.<h2>form</h2>
<form onsubmit="alert('submit 성공?')">
<input type="text" name="username">
<button type="submit">제출하기</button>
</form>
<h2>Image</h2>
<img src="image.jpg" alt="이미지" />
<form> 요소는 사용자 입력을 받기 위한 HTML 폼을 정의한다.진행(progress) 이벤트
error 이벤트를 간단하게 설명하고 넘어가자<img src="image.jpg" alt="이미지" />
주소를 잘못 입력한 img 태그가 하나 있다. 주소를 잘 못 입력했더니
이렇게 출력되는 것을 확인할 수 있다.
이러한 에러를 처리할 코드를 한 번 작성해보자
img.addEventListener('error', () => {
console.log('error!');
});
img에 이벤트를 부여했는데, error가 발생했을 시, console에 error! 를 출력하도록 했다
이때, 이미지 로딩에 실펴하면,
이미지의 기본값을 설정해두어 화면에 출력해보도록 하면 어떨까?
img.addEventListener('error', (e) => {
console.log('error!');
img.src = '../img/apple.jpg';
});
img에 error 가 발생한다면, img의 src의 값을 '../img/apple.jpg'로 변경하라! 라는 의미이다.
사과 이미지가 정상적으로 출력되는 것을 확인할 수 있다!