본문 바로가기
JavaScript

자바스크립트#07 : 문서 객체 모델

by haheehee 2022. 12. 20.

DOMContentLoaded 이벤트를 사용한 문서 객체 조작과 다양한 이벤트

 

문서 객체를 조합해서 만든 전체적인 형태인

문서 객체 모델(Document Objects Model)을 조작하는 방법을 정리해보겠다.

 

Document Objects Model을 이용할 때는, 

HTML문서의 태그들을 객체로 생각하고 이해하면 된다.


HTML 코드를 자바스크립트로 조작해보기

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>DOMContentLoaded Event</title>
<script>
	// HTML 태그를 쉽게 만들 수 있는 콜백 함수 선언
	const h1 = (text) => `<h1>${text}</h1>`
</script>
<script>
	// body 태그가 생성되기 이전에 script 태그로 body 태그를 조작
	// 앞에서 선언한 h1 함수를 실행
	document.body.innerHTML += h1(`1번째 script 태그`)
</script>
</head>
<body>
	<script>
		document.body.innerHTML += h1(`2번째 script 태그`)
	</script>
	<h1>1번째 h1 태그</h1>
	<script>
		document.body.innerHTML += h1(`3번째 script 태그`)
	</script>
	<h1>2번째 h2 태그</h1>
</body>
</html>

HTML 코드를 자바스크립트로 조작해보기

body 태그는 head태그 다음에 생성된다.

document는 웹페이지


DOMContentLoaded 이벤트

- DOMContentLoaded 이벤트는 웹 브라우저가 문서 객체를 모두 읽고 나서 실행하는 이벤트이다.

- DOMContentLoaded 상태가 되었을 때, 콜백 함수 호출!

<script>
	// DOMContentLoaded 이벤트를 연결합니다. 
	document.addEventListener('DOMContentLoaded', () => {
		const h1 = (text) => `<h1>${text}</h1>`
		document.body.innerHTML += h1(`DOMContentLoaded 이벤트 발생`)
	})
</script>

DOMContentLoaded 이벤트

addEventListener로 이벤트가 발생하면, 

매개변수 `DOMContentLoaded`로부터 head, body, ...등 모든 태그들(객체들)이 모두 로드되었을 때,

두 번째 매개변수인 콜백함수(익명함수)가 실행된다. 

- 여기서 콜백함수란, 매개변수로 들어가는 함수를 의미한다.

- 정리하면, 문서 객체를 모두 읽어들이면(DOMContentLoaded), 콜백함수가 실행된다.

- 콜백함수의 첫 번째 실행문 (const h1 = (text) => `<h1>${text}</h1>`) 은 text를 받아서 h1에 넣기


문서 객체 가져오기

- document.body 코드를 사용하여 문서의 태그 읽기

      document.head

      document.body

      document.title

- head 요소와 body 요소 내부에 만든 다른 요소들은 별도의 메소드가 필요하다.

      document.querySelector(선택자)

      document.querySelectorAll(선택자)

!!!중요한 예시이니 전체적인 틀 숙지하기!!!

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const header = document.querySelector(`h1`)
	
		header.textContent = `HEADERS`
		header.style.color = `white`
		header.style.backgroundColor = `black`
		header.style.padding = `10px`
	})
</script>

 

addEventListener로 이벤트 모델을 실행

첫 번째 매개변수 `DOMContentLoaded` 문서의 모든 태그(객체)를 로드할 때, (이벤트가 발생하면 콜백함수 호출)

두 번째 매개변수인 콜백함수(익명함수)를 호출한다.

- 콜백함수의 첫 번째 실행문(const header = document.querySelector(`h1`))

               : body태그의 h1태그의 주소를 header 상수에 넣는다.,

                여기서 querySelector의 매개변수는 tab키 위 ``로 넣어야 한다.

- 콜백함수의 그 밑 실행문들 : h1 태그 안에 문자열 넣기, 텍스트 색과 배경색 변경, 패딩 설정

               여기서 .style은 클래스로, .color, .backgroundColor, .padding은 속성들로 생각하면 된다.

문서 객체 가져오기

- querySelectorAll(`h1`)은 body태그 안의 모든 h1에 적용하는 것!


글자 조작하기

글자 조작하기

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const a = document.querySelector(`#a`)
		const b = document.querySelector(`#b`)
		
		a.textContent = `<h1>textContent 속성</h1>`
		b.innerHTML = `<h1>innerHTML 속성</h1>`
	})
</script>
</head>
<body>
	<div id = "a"></div>
	<div id = "b"></div>
</body>
</html>

글자 조작하기


속성 조작하기

속성 조작하기

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const rects = document.querySelectorAll(`.rect`)
		
		rects.forEach((rect, index) => {
			const width = (index + 1) * 100
			const src = `http://placekitten.com/${width}/250`
			rect.setAttribute('src', src)
		})
	})
</script>
</head>
<body>
	<img class="rect">
	<img class="rect">
	<img class="rect">
	<img class="rect">
</body>
</html>

 

속성 조작하기

rect.setAttribute('src', src)에서

첫 번째 매개변수인 'src'는 img 태그의 src속성을 의미하고

두 번째 매개변수인 src는 그 윗줄의 const src를 의미한다.


스타일 조작하기

스타일 조작하기

스타일 조작법

1. h1.style.backgroundColor

2. h1.style['backgroundColor']

3. h1.style['background-color']

div.style.backgroundColor = `rgba(${val}, ${val}, ${val})` 이러한 형태로 사용하면 된다.


문서 객체 생성하기

- document.createElement(문서_객체_이름) 메서드

- 문서 객체 트리 구조

     문서를 어떤 문서 아래에 추가할지 지정하는 것

      부모객체.appendChild(자식_객체)

 

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>DOMContentLoaded Event</title>
<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const divA = document.querySelector(`#first`)
		const divB = document.querySelector(`#second`)
		const h1 = document.createElement(`h1`)
		h1.textContent = `이동하는 h1 태그`
	
		const toFirst = () => {
			divA.appendChild(h1)
			setTimeout(toSecond, 1000)
		}
		const toSecond = () => {
			divB.appendChild(h1) 
			setTimeout(toFirst, 10000)
		}
		toFirst()
	})
</script>
</head>
<body>
	<div id="first">
		<h1>첫 번째 div 태그 내부</h1>
	</div>
	<hr>
	<div id="second">
		<h1>두 번쨰 div 태그 내부</h1>
	</div>
</body>
</html>

문서 객체 생성하기 처음, 그리고 11초뒤
문서 객체 생성하기 1초뒤

const header = document.createElement('h1') 로 h1 태그를 생성하고

document.body.appendChild(header) 로 h1 태그를 body 태그 아래에 추가

문서 객체의 부모는 하나여야 한다. 

문서 객체를 다른 문서 객체에 추가하면 문서 객체가 이동


문서 객체 제거하기

- 부모객체.removeChild(자식객체: 문서 객체를 제거

- 문서객체.parentNode.removeChild(문서객체: appendChild() 함수 등으로 부모 객체와 이미 연결이 완료된 문서객체의 경우, parentNode 속성으로 부모 객체에 접근할 수 있다. 이때 사용하는 코드

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		setTimeout(() => {
			const h1 = document.querySelector(`h1`)
			
			h1.parentNode.removeChild(h1)
		}, 3000)
	})
</script>
</head>
<body>
	<hr>
	<h1>제거 대상 문서 객체</h1>
	<hr>
</body>
<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		setTimeout(() => {
			const h1 = document.querySelector(`h1`)

			document.body.removeChild(h1)
		}, 3000)
	})
</script>
</head>
<body>
	<hr>
	<h1>제거 대상 문서 객체</h1>
	<hr>
</body>

두 가지 코드 모드 같은 동작. (3초 후 h1텍스트 제거)


이벤트 설정하기 & 이벤트 제거하기

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>DOMContentLoaded Event</title>
<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		let counter = 0
		let isConnect = false
		
		const h1 = document.querySelector(`h1`)
		const p = document.querySelector(`p`)
		const connectButton = document.querySelector(`#connect`)
		const disconnectButton = document.querySelector(`#disconnect`)
		
		const listener = (event) => {
			h1.textContent = `클릭 횟수 : ${counter++}`
		}
		
		connectButton.addEventListener(`click`, () => {
			if(isConnect === false) {
				h1.addEventListener(`click`, listener)
				p.textContent = `이벤트 연결 상태 : 연결`
				isConnect = true
			}
		})
		
		disconnectButton.addEventListener(`click`, () => {
			if(isConnect === true) {
				h1.removeEventListener(`click`, listener)
				p.textContent = `이벤트 연결 상태 : 해제`
				isConnect = false
			}
		})
	})
</script>
<style>
h1 {
	user-select: none;
}
</style>
</head>
<body>
	<h1>클릭 횟수: 0</h1>
	<button id="connect">이벤트 연결</button>
	<button id="disconnect">이벤트 제거</button>
	<p>이벤트 연결 상태: 해제</p>
</body>
</html>

이벤트 제거하기
이벤트 설정하기

.addEventListener로 이벤트가 발생하면

`DOMContentLoaded`로 모든 태그들(객체)가 모두 로드되었을 때, 콜백함수(익명함수) 실행

const h1, p : 태그 선택자(문서객체)를 가져와 상수에 넣기.

const connectButton, disconnectButton : id선택자 connect와 disconnect인 버튼을 가져와 상수에 넣기.

const listener : 익명함수를 여러 번 사용하기 위해 밖으로 빼서 listener라는 상수에 넣음. 이벤트가 발생하면 counter변수를 1씩 증가시켜 h1 text에 적용하고 출력

connectButton.addEventListener : #connect버튼에 click 이벤트가 발생하면 콜백함수 실행. isConnect 변수가 false이면, if문 실행. 마지막에 true반환. h1에 click 이벤트인 위에서 const listener로 선언해준 익명함수 실행. p 텍스트 "연결"로 변경.

disconnectButton.addEventListener : #disconnect버튼에 click이벤트가 발생하면 콜백함수 실행. isConnect변수가 true이면, if문 실행. 마지막에 false 반환. h1에 click이벤트 제거. p텍스트"해제"로 변경. 

<style>태그 안 : h1 요소 드래그했을 때 드래그 되는 것을 방지하기 위하여 user-select: none;


키보드 이벤트 설정하기

.addEventListener(`keyup`, (event) => {  ....  }

textarea.addEventListener(`keyup`, (event) => {
	const length = textarea.value.length
	h1.textContent = `글자 수 : ${length}`
})

value.length : value 속성으로 글자 수를 읽을 수 있다. 

키보드 이벤트 설정하기


키보드 키 코드 사용하기

키보드 키 코드 사용하기

- code 속성은 입력한 키를 나타내는 문자열이 들어 있다.

- altKey, ctrlKey, shiftKey 속성은 해당 키를 눌렀는지 불 자료형 값이 들어 있다.

출처 :&nbsp;https://forums.tumult.com/

키코드를 사용하여 어떤 키가 눌렸는지 확인해보기

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const h1 = document.querySelector(`h1`)
		const print = (event) => {
			let output = ""
			output += `alt: ${event.altKey}<br>`
			output += `ctrl: ${event.ctrlKey}<br>`
			output += `shift: ${event.shiftKey}<br>`
			output += `code: ${typeof(event.code) !== `undefined` ? event.code : event.keyCode}<br>`
			
			h1.innerHTML = output
		}
		
		document.addEventListener(`keydown`, print)
		document.addEventListener(`keyup`, print)
	})
</script>

키코드를 사용하여 어떤 키가 눌렸는지 확인해보기

output += `alt: ${event.altKey}<br>`
output += `ctrl: ${event.ctrlKey}<br>`
output += `shift: ${event.shiftKey}<br>`
output += `code: ${typeof(event.code) !== `undefined` ? event.code : event.keyCode}<br>`

-> 이부분 : 이벤트가 발생하면 불 값을 반환!!!

 

document.addEventListener(`keydown`, print)
document.addEventListener(`keyup`, print)

-> 키가 눌릴 때 출력하고, 키가 떨어질 때도 출력!

 

키코드를 사용하여 어떤 키가 눌렸는지 확인해보기

키코드로 별 움직이기

<script>
	document.addEventListener(`DOMContentLoaded`, () => { 
		// 별 초기설정
		const star = document.querySelector(`h1`)
		star.style.position = `absolute`
		
		// 별의 이동 출력
		let [x, y] = [0, 0]
		const block = 20
		const print = () => {
			star.style.left = `${x * block}px`
			star.style.top = `${y * block}px`
		}
		print()
		
		// 별 이동
		const [left, up, right, down] = [37, 38, 39, 40]
		document.body.addEventListener(`keydown`, (event) => { 
			switch (event.keyCode) {
				case left:
					x-=1 
					break;
				case up: 
					y-=1
					break;
				case right:
					x+=1
					break;
				case down:
					y+=1
					break;
			}
			print()
		})
	})
</script>

키코드로 별 움직이기

star.style.position = 'absolute

-> style 속성을 조작해서 position 값을 설정

const [left, up, right, down] = [37, 38, 39, 40]

-> 방향키 키코드를 배열에 넣어서 문자열로 변환(사용하기 쉽도록) 

document.body.addEventListener('keydown', (event) => { ... }

-> 키보드가 눌릴 때 실행되도록 이벤트 설정


이벤트 발생 객체

- 이벤트 리스너 내부에서 어떤 변수에 접근할 수 없을 때 

1. event.currentTarget 속성 사용

2. this 키워드 사용

 

- 이벤트 리스너 내부에서 어떤 변수에 접근할 수 없을 때

<script>
	const listener = (event) => {
		const length = textA.value.length
		h1.textContent = `글자 수 : ${length}`
	}
	
	document.addEventListener(`DOMContentLoaded`, () => {
		const textA = document.querySelector(`textA`)
		const h1 = document.querySelector(`h1`)
		textA.addEventListener(`keyup`, listener)
	})
</script>

이벤트 리스너 내부에서 &nbsp; 어떤 변수에 접근할 수 없을 때 (콘솔 창)

listener 내부에서 textA에 접근할 수 없다. 

 

1. event.currentTarget 속성 사용

<script>
	const listener = (event) => {
		const length = event.currentTarget.value.length
		const h1 = document.querySelector(`h1`)
		h1.textContent = `글자 수: ${length}`
	}
	
	document.addEventListener(`DOMContentLoaded`, () => {
		const textA = document.querySelector(`textarea`)
		textA.addEventListener(`keyup`, listener)
	})
</script>

<body>
	<h1>글자 수</h1>
	<textarea></textarea>
</body>

event.currentTarget이 textarea가 된다.

 

2. this 키워드 사용

<script>
	const listener = function (event) {
		const length = this.value.length
		const h1 = document.querySelector('h1')
		h1.textContent = `글자 수: ${length}`
	}
	
	document.addEventListener(`DOMContentLoaded`, () => {
		const textarea = document.querySelector('textarea')
		textarea.addEventListener('keyup', listener)
	})
</script>

<body>
	<h1></h1>
	<textarea></textarea>
</body>

this는 람다식 안됨!!! -> 표준 형식으로만 가능

this가 textarea가 된다. (현재의 위치)

textarea.addEventListener('keyup', listener)      : textarea가 keyup이 되는지 보는 중. -> keyup이 되면 listener 호출


글자 입력 양식 이벤트

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const input = document.querySelector(`input`)
		const button = document.querySelector(`button`)
		const p = document.querySelector(`p`)
		
		button.addEventListener(`click`, () => {
			const inch = Number(input.value)
			if(isNaN(inch)) {
				p.textContent = `숫자를 입력해주세요`
				return
			}
			const cm = inch * 2.54
			p.textContent = `${cm} cm`
		})
	})
</script>

document.addEventListener(`DOMContentLoaded`, () => { ... }

                  : document는 웹페이지

const input = document.querySelector(`input`)       : input태그의 주소를 const input에 넣는다.

const inch = Number(input.value)          : Number(..)은 생성자. input.vale는 string 형! -> Number()생성자로 숫자로 바꿔줌

p.textContent = ...           : innertext보다 textContent가 더 많은 지원이 있으니 되도록 textContent쓰기

글자 입력 양식 이벤트

 

유효성 검사

정규표현식(regular expression)을 사용한다.

인터넷에서 특정 사이트에 가입할 때 e-mail과 전화번호 등의 유효성 검사가 필요하다.

const isEmail = (value) => {
	return (value.indexOf(`@`) > 1) && (value.split(`@`)[1].indexOf(`.`) > 1)
}

이메일인지 검사

1. value.indexOf(`@`) > 1         : @앞에 문자가 있는지 확인

2. value.split(`@`)[1].indexOf(`.`) > 1            : split으로 @ 앞뒤로의 문자열을 배열 0인덱스와 1인덱스에 나누어 넣어준 후,

                                                                    `.`앞에 문자가 있는지 확인

 

 

드롭다운 목록

select 태그

multiple 선택 예제

<script>
	document.addEventListener(`DOMContentLoaded`, () => {
		const select = document.querySelector(`select`)
		const p = document.querySelector(`p`)
		
		select.addEventListener(`change`, (event) => {
			const options = event.currentTarget.options
			const list = []
			for(const option of options) {
				if(option.selected) {
					list.push(option.textContent)
				}
			}
			p.textContent = `선택 : ${list.join(`,`)}`
		})
	})
</script>

<body>
	<select multiple>
		<option>떡볶이</option>
		<option>순대</option>
		<option>오뎅</option>
		<option>튀김</option>
	</select>
	<p></p>
</body>

options 속성에는 forEach()메소드가 없으므로, 반복문을 사용하여야 한다.

option.selected -> selected 속성을 확인하여 선택되었으면 리스트에 넣어줌.

select 태그 multiple 선택 예제

그런데 선택할 때, 컨트롤 혹은 드래그로 해야 중복 선택해야 하는 문제가 있다.

 

체크박스

true혹은 false가 불형으로 자동으로 나온다.

<script>
	document.addEventListener('DOMContentLoaded', () => {
		let[timer, timerId] = [0, 0]
		const h1 = document.querySelector('h1')
		const checkbox = document.querySelector('input')
		
		checkbox.addEventListener('change', (event) => {
			if(event.currentTarget.checked) {
				timerId = setInterval(() => {
					timer += 1
					h1.textContent = `${timer}초`
				}, 1000)
			} else {
				clearInterval(timerId)
			}
		})
	})
</script>

<body>
	<input type="checkbox">
	<span>타이머 활성화</span>
	<h1></h1>
</body>

<input type="checkbox">

event.currentTarget.checked       : checked 속성 사용해서 체크박스(event.currentTarget)이 체크되어있는지 확인.

                                                      true : 체크되어있음. / false : 체크 안되어있음.

setInterval( ..., 1000)     : 구간. 1000ms(1s)마다

clearInterval(체크해제할변수)        : 체크 해제

체크박스

 

라디오 버튼

<input>태그 안에 속성 type="radio"를 넣어서 라디오 버튼을 생성.

<input>태그 안에 속성 type, name, value를 넣어서 생성하기

<script>
	document.addEventListener('DOMContentLoaded', () => {
		const output = document.querySelector('#output')
		const radios = document.querySelectorAll('[name=pet]')
		
		radios.forEach((radio) => {
			radio.addEventListener('change', (event) => {
				const current = event.currentTarget
				if(current.checked) {
					output.textContent = `좋아하는 반려동물은 ${current.value}이시군요!`
				}
			})
		})
	})
</script>

<body>
	<h3>** 좋아하는 반려동물을 선택해주세요 **</h3>
	<input type="radio" name="pet" value="강아지">
	<span>강아지</span>
	<input type="radio" name="pet" value="고양이">
	<span>고양이</span>
	<input type="radio" name="pet" value="햄스터">
	<span>햄스터</span>
	<input type="radio" name="pet" value="기타">
	<span>기타</span>
	<hr>
	<h3 id="output"></h3>
</body>

html에서 radio의 name속성값은 모두 동일해야 함! (name속성을 동일하게 입력해 그룹으로 만듦)

radios.forEach(...)       : 모든 라디오 버튼에

라디오 버튼


기본 이벤트 막기

어떤 이벤트가 발생했을 때, 웹 브라우저가 기본적으로 처리해주는 것을 기본이벤트라 한다.

 

1 .기본 이벤트 막기 (이미지)

<script>
	document.addEventListener('DOMContentLoaded', () => {
		const imgs = document.querySelectorAll('img')
		
		imgs.forEach((img) => {
			img.addEventListener('contextmenu', (event) => {
				event.preventDefault()
			})
		})
	})
</script>

<body>
	<img src="http://placekitten.com/300/300" alt="kitten">
</body>

첫번째 예제는 이미지부분에 오른쪽 마우스를 클릭하면 나오는 것을 없애는 코드이다.

마우스오른쪽버튼

이미지에 contextmenu가 호출되면 콜백함수 호출

preventDefault()를 사용하여 컨텍스트 메뉴를 출력하는 기본 이벤트를 제거(무효처리)

 

2. 기본이벤트 막기 (링크연결)

<script>
	document.addEventListener('DOMContentLoaded', () => {
		let status = false
		
		const checkbox = document.querySelector('input')
		checkbox.addEventListener('change', (event) => {
			status = event.currentTarget.checked
		})
		
		const link = document.querySelector('a')
		link.addEventListener('click', (event) => {
			if(!status) {
				event.preventDefault()
			}
		})
	})
</script>

기본이벤트 막기 (링크연결)

checkbox의 checked속성을 활용하여, preventDefault를 통하여 체크박스에 체크가 되었을 때에만 링크를 연결하도록 함

여기서 checkbox는 input태그의 type속성으로,

링크는 a태그의 href 속성으로 생성하면 된다.


타이머로 글자 수 세기

<script>
	document.addEventListener('DOMContentLoaded', () => {
		const textarea = document.querySelector('textarea')
		const h1 = document.querySelector('h1')
		let timerId
		
		textarea.addEventListener('focus', (event) => {
			timerId = setInterval(() => {
				const length = textarea.value.length
				h1.textContent = `글자 수 : ${length}`
			}, 50)
		})
		textarea.addEventListener('blur', (event) => {
			clearInterval(timerId)
		})
	})
</script>

'focus'                    : textarea 영역이 활성화 되었을 때

'blur'                       : textarea 영역이 비활성화 되었을 때

setInterval(..., 50)  : 0.05초 간격으로 ...실행

글자수 세기

 

localStorage 객체

웹 브라우저에 데이터 저장하는 객체

- localStorage.getItem(key)                   : 저장된 값 get(추출), 없으면 undefined

                                                                 객체 속성 추출

- localStorage.setItem(key, value)          : 값 저장. 객체에 속성을 지정하는 형태로도 사용

- localStorage.removeItem(key)             : 특정 키 값 제거

- localStorage.clear()                              : 저장된 모든 값 제거

한시적으로 사용! 더 방대한 양의 데이터는 mariaDB로 사용한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

출처 : 혼자 공부하는 자바스크립트 (윤인성)

 

댓글