728x90
반응형
Chap 7 문서 객체 모델
1. 문서 객체 조작하기
- HTML 페이지에 있는 html, head, body, title, h1, div, span 등을 HTML 언어에서는 요소라고 부름
- 자바스크립트에서는 이를 문서 객체라고 부른다
- 따라서 문서 객체를 조작한다는 말을 HTML 요소들을 조작한다는 의미
- 문서 객체 모델 (DOM, Document Objects Model)
- 문서 객체를 조합해서 만든 전체적인 형태
- 제이쿼리와 같은 라이브러리와 리액트와 같은 프레임워크를 사용하기 때문에 조작이 쉬움
1) DOMContentLoaded 이벤트
- 문서 객체를 조작할 때 사용하는 이벤트
- 오탈자를 입력해도 오류를 발생하지 않으니 절대 틀리지말고 입력하길!
HTML 코드를 자바스크립트로 조작하기 |
<!DOCTYPE html>
<html>
<head>
<title>DOMContentLoaded</title>
<script>
// HTML 태그를 쉽게 만들 수 있는 콜백 함수를 선언합니다.
const h1 = (text) => `<h1>${text}</h1>`
</script>
<script>
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>
|
- body 태그가 생성되기 이전에 head 태그 안의 script 태그에서 body 태그를 조작하던 부분
(<h1>1번째 script 태드</h1>를 출력하는 부분)은 화면에 출력되지 않음 - 기본적으로 head 태그 내부에 script 태그를 배치하면 body 태그에 있는 문서 객체(요소)에 접근할 수 없음
- head 태그 내부의 script 태그에서 body 태그에 있는 문서에 접근하려면 화면에 문서 객체(요소)를
모두 읽어들일 때까지 기다려야 함 - DOMContentLoaded 이벤트는 웹 브라우저가 문서 객체를 모두 읽고 나서 실행하는 이벤트
DOMContentLoaded 이벤트 |
<!DOCTYPE html>
<html>
<head>
<title>DOMContentLoaded</title>
<script>
// DOMContentLoaded 이벤트를 연결합니다.
document.addEventListener('DOMContentLoaded', () => {
const h1 = (text) => `<h1>${text}</h1>`
document.body.innerHTML += h1('DOMContentLoaded 이벤트 발생')
})
</script>
</head>
<body>
</body>
</html>
|
2) 문서 객체 가져오기
- document.body 코드를 사용하면 body 요소를 읽어들일 수 있다
- 이외에도 HTML 문서에 있는 head 요소와 title 요소 등은 다음과 같은 방법으로 읽어들일 수 있다.
- 우리가 head 요소와 body 요소 내부에 만든 다른 요소들은 다음과 같은 별도의 메소드를 사용해서 접근
- 선택자 부분에는 CSS 선택자를 입력
- CSS 선택자는 매우 다양
- querySelector()
- querySelectorAll()
querySelector() 메소드 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<h1></h1>
</body>
</html>
|
- querySelector() :: h1 태그를 추출하고 조작하는데 사용됨
querySelectorAll() 메소드 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 요소를 읽어들입니다.
const headers = document.querySelectorAll('h1')
// 텍스트와 스타일을 변경합니다.
headers.forEach((header) => {
header.textContent = 'HEADERS'
header.style.color = 'white'
header.style.backgroundColor = 'black'
header.style.padding = '10px'
})
})
</script>
</head>
<body>
<h1></h1>
<h1></h1>
<h1></h1>
<h1></h1>
</body>
</html>
|
- querySelectorAll() :: 문서 객체 여러 개를 배열로 읽어들이는 함수
- 따라서 내부의 요소에 접근하고 활용하려면 반복을 돌려야함
- 일반적으로 forEach() 메소드를 사용해서 반복을 돌림
3) 글자 조작하기
- 지금까지 살펴본 예제들에서 innerHTML 속성, textContent 속성을 사용해서 문서 객체 내부의 글자를 조작
속성 이름 | 설명 |
문서 객체.textContent | 입력된 문자열을 그대로 넣습니다. |
문서 객체.innerHTML | 입력된 문자열을 HTML 형식으로 넣습니다 |
- textContent 속성은 입력된 문자열을 그대로 넣어줌
- innerHTML 속성은 입력된 문자열을 HTML 형식으로 넣어줌
글자 조작하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
|
- textContent 속성은 글자가 그대로 들어갔지만, innerHTML 속성은 <h1>~</h1>을 h1 요소로 변환해서 들어갔음
4) 속성 조작하기
메소드 이름 | 설명 |
문서 객체.setAttribute(속성이름, 값) | 특성 속성에 값을 지정한다. |
문서 객체.getAttribute(속성이름) | 특정 속성을 추출합니다. |
속성 조작하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const rects = document.querySelectorAll('.rect')
rects.forEach((rect, index) => {
const width = (index + 1) * 100
rect.setAttribute('src', src)
})
})
</script>
</head>
<body>
<img class="rect">
<img class="rect">
<img class="rect">
<img class="rect">
</body>
</html>
|
- setAttribute()와 getAttribute()메소드를 사용하지 않고도 온점을 찍고 속성을 바로 읽어들이거나 지정 가능
5) 스타일 조작하기
- 문서 객체의 스타일을 조작할 때는 style 속성을 사용
- style 속성은 객체이며, 내부에는 속성으로 CSS를 사용해서 지정할 수 있는 스타일들이 있음
- 이러한 속성에는 CSS로 입력할 때 사용하는 값과 같은 값을 입력
- 자바스크립트에서는 - 기호를 식별자에 사용할 수 없으므로,
두 단어 이상의 속성은 다음과 같이 캐멀 케이스로 나타냄
CSS 속성 이름 | 자바스크립트 style 속성 이름 |
background-color | backgroundColor |
text-align | textAlign |
font-size | fontSize |
스타일 조작하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const divs = document.querySelectorAll('body > div')
divs.forEach((div, index) => {
console.log(div, index)
const val = index * 10
div.style.height = `10px`
div.style.backgroundColor = `rgba(${val}, ${val}, ${val})`
})
})
</script>
</head>
<body>
<!-- div 태그 25개 -->
<div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div><div></div>
</body>
</html>
|
6) 문서 객체 생성하기
- 문서 객체를 생성하고 싶을 때에는 document.createElement() 메소드를 사용한다.
- 그런데 문서 객체를 만들었다고 문서 객체가 배치되는 것은 아님
- 문서를 어떤 문서 아래에 추가할지를 지정해줘야함
- 이러한 그림을 프로그래밍에서 트리(tree)라고 부름
- 어떤 문서 객체가 있을 때 위에 있는 것을 부모(parent)라고 부르고, 아래에 있는 것을 자식(child)라고 부름
- 문서 객체에는 appendChild() 메소드가 있으며, 이를 활용하면 어떤 부모 객체 아래에 자식 객체를 추가할 수 있음
- 문서 객체 트리 구조를 만드는 방법은 다음과 같음
문서 객체 생성하고 추가하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 문서 객체 생성하기
const header = document.createElement('h1')
// 생성한 태그 조작하기
header.textContent = '문서 객체 동적으로 생성하기'
header.setAttribute('data-custom', '사용자 정의 속성')
header.style.color = 'white'
header.style.backgroundColor = 'black'
// h1 태그를 body 태그 아래에 추가하기
document.body.appendChild(header)
})
</script>
</head>
<body>
</body>
</html>
|
7) 문서 객체 이동하기
- appendChild() 메소드는 문서 객체를 이동할 때도 사용할 수 있음
- 문서 객체의 부모는 언제나 하나여야 한다.
- 따라서 문서 객체를 다른 문서 객체에 추가하면 문서 객체가 이동
문서 객체 이동하기 |
<!DOCTYPE html>
<html>
<head>
<title></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>
|
8) 문서 객체 제거하기
- 문서 객체를 제거할 때는 removeChild() 메소드를 사용
- appendChild() 메소드 등을 부모 객체와 이미 연결이 완료된 문서 객체의 경우 parentNode 속성으로 부모 객체에 접근
- 일반적으로 어떤 문서 객체를 제거할 떄는 다음과 같은 형태의 코드를 사용
문서 객체 제거하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
const h1 = document.querySelector('h1')
h1.parantNode.removeChild(h1)
// document.body.removeChild(h1)
}, 3000)
})
</script>
</head>
<body>
<hr>
<h1>제거 대상 문서 객체</h1>
<hr>
</body>
</html>
|
9) 이벤트 설정하기
- 모든 문서 객체는 생성되거나 클릭되거나 마우스를 위에 올리거나 할 때 이벤트라는 것이 발생
- 이 이벤트가 발생할 때 실행할 함수는 addEventListener() 메소드를 사용
- 이벤트가 발생할 때 실행할 함수를 이벤트 리스너(event listener) 또는 이벤트 핸드러(event handler)라고 부름
이벤트 연결하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
let counter = 0
const h1 = document.querySelector('h1')
h1.addEventListener('click', (event) => {
counter++
h1.textContent = `클릭 횟수:${counter}`
})
})
</script>
<style>
h1{
/* 클릭을 여러 번 했을 때
글자가 선택되는 것을 막기 위한 스타일 */
user-select: none;
}
</style>
</head>
<body>
<h1>클릭 횟수: 0</h1>
</body>
</html>
|
- 이벤트를 제거할 때는 removeEventListener() 메소드를 활용
- 이벤트 리스너 부분에는 연결할 때 사용했던 이벤트 리스너를 넣는다.
- 변수 또는 상수로 이벤트 리스너를 미리 만들고, 이를 이벤트 연결과 연결 제거에 활용
이벤트 연결 제거하기 |
<!DOCTYPE html>
<html>
<head>
<title></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 = '이벤트 연결 상태: 해제'
}
})
})
</script>
<style>
h1{
/* 클릭을 여러 번 했을 때
글자가 선택되는 것을 막기 위한 스타일 */
user-select: none;
}
</style>
</head>
<body>
<h1>클릭 횟수: 0</h1>
<button id="connect">이벤트 연결</button>
<button id="disconnect">이벤트 제거</button>
<p>이벤트 연결 상태: 해제</p>
</body>
</html>
|
2.이벤트 활용
- 입력 양식(form)에 관련된 내용을 많이 사용
- 입력 양식에 관련된 내용을 알기 위해서는 사전에 HTML 기본에 대한 공부가 많이 필요
1) 이벤트 모델
- 이벤트를 연결하는 방법을 이벤트 모델이라고 부름
- 이벤트를 연결할 때 addEventListener() 메소드를 사용 → 표준 이벤트 모델
- 고전 이벤트 모델 :: on○○으로 시작하는 속성에 함수를 할당해서 이벤트를 연결하는 방법
- 인라인 이벤트 모델 :: 고전 이벤트 모델처럼 onOO으로 시작하는 속성을
HTML 요소에 직접 넣어서 이벤트를 연결하는 것
- 인라인 이벤트 모델은 HTML 요소의 onOO 속성에 자바스크립트 코드를 넣는 것
- 현재 코드에서는 listener()라는 함수를 호출하고 있음
- 이때 onOO 속성 내부에서 변수 event를 활용할 수 있음
- 이 변수를 listener() 함수의 매개변수로 전달
- 모든 이벤트 모델의 이벤트 리스너는 첫 번째 매개변수로 이벤트 객체를 받는다.
2) 키보드 이벤트
이벤트 | 설명 |
keydown | 키가 눌릴 때 실행. 키보드를 꾹 누르고 있을 때도, 입력될 때도 실행됨 |
keypress | 키가 입력되었을 때 실행 웹브라우저에 따라서 아시아권의 문자(한중일)를 제대로 처리하지 못하는 문제가 있음 |
keyup | 키보드에서 키가 떨어질 때 실행 |
- keydown 이벤트와 keypress 이벤트는 웹 브라우저에 따라서 아시아권의 문자를 제대로 처리하지 못하는 문제가 있어
일반적으로는 keyup 이벤트를 사용함.
남은 글자 수 출력하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const textarea = document.querySelector('textarea')
const h1 = document.querySelector('h1')
textarea.addEventListener('keyup', (event) => {
const length = textarea.value.length
h1.textContent = `글자 수: ${length}`
})
})
</script>
</head>
<body>
<h1></h1>
<textarea></textarea>
</body>
</html>
|
- keypress 이벤트로 구현하면 아시아권의 문자는 공백이 들어가기 전까지는 글자 수를 세지 않는다.
- 아예 keypress 이벤트가 발생하지 않는다.
- keyup 이벤트는 키가 키보드에서 떨어질 때 발생
→ 특정 키를 꾹 누르고 있으면 글자 수를 세지 않는다.
(1) 키보드 키 코드 사용하기
- 키보드 이벤트가 발생할 때는 이벤트 객체로 어떤 키를 눌렀는지와 관련된 속성들이 따라옴
이벤트 속성 이름 | 설명 |
code | 입력한 키 |
keyCode | 입력한 키를 나타내는 숫자 |
altKey | Alt 키를 눌렀는지 |
ctrlKey | Ctrl 키를 눌렀는지 |
shiftKey | Shift 키를 눌렀는지 |
- code 속성은 입력한 키를 나타내는 문자열이 들어있고, altKey, ctrlKey, shiftKey 속성은 해당 키를 눌렀는지 불 자료형 값이 들어있음
키보드 이벤트와 관련된 이벤트 속성 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<h1></h1>
</body>
</html>
|
키로 별 움직이기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<h1>★</h1>
</body>
</html>
|
3) 이벤트 발생 객체
- 코드의 규모가 커지면 이처럼 이벤트 리스너를 외부로 분리하는 경우가 많아짐
- 해결 방법
- event.currentTarget 속성을 사용
- () => {} 와 function () {} 형태 모두 사용이 가능
- this 키워드 사용
- 화살표 함수가 아닌 function () {} 형태로 함수를 선언한 경우에 사용
- event.currentTarget 속성을 사용
4) 글자 입력 양식 이벤트
- 사용자로 부터 어떠한 입력을 받을 때 사용하는 요소를 입력 양식(form)이라고 부름.
- HTML에서는 input 태그, textarea 태그, button 태그, select 태그 등이 모두 입력 양식
입력 양식을 기반으로 inch를 cm 단위로 변환하는 프로그램 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<input type="text"> inch<br>
<button>계산</button>
<p></p>
</body>
</html>
|
- isNaN() 함수의 결과가 true로 나오는 숫자가 아닌 경우 바로 return 키워드로 리턴해서 이후의 코드를 실행하지 않음
- 위와 같이 사용하면 들여쓰기 단계를 하나 줄일 수 있으므로 코드가 깔끔해짐
이메일 형식 확인하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const input = document.querySelector('input')
const p = document.querySelector('p')
const isEmail = (value) => {
// 골뱅이를 갖고 있고 && 골뱅이 뒤에 점이 있다면
return (value.indexOf('@') > 1)
&& (value.split('@')[1].indexOf('.') > 1)
}
input.addEventListener('keyup', (event) => {
const value = event.currentTarget.value
if (isEmail(value)) {
p.style.color = 'green'
p.textContent = `이메일 형식입니다: ${value}`
} else {
p.style.color = 'red'
p.textContent = `이메일 형식이 아닙니다: ${value}`
}
})
})
</script>
</head>
<body>
<input type="text">
<p></p>
</body>
</html>
|
- ismail() :: indexOf() 함수 등을 활용해서 매개변수로 전달된 값이 이메일인지 확인하고 true 또는 false를 리턴함.
(1) 드롭다운 목록 활용하기
- select 태그로 구현
기본 select 태그 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const select = document.querySelector('select')
const p = document.querySelector('p')
select.addEventListener('change', (event) => {
const options = event.currentTarget.options
const index = event.currentTarget.options.selectedIndex
p.textContent = `선택: ${options[index].textContent}`
})
})
</script>
</head>
<body>
<select>
<option>떡볶이</option>
<option>순대</option>
<option>오뎅</option>
<option>튀김</option>
</select>
<p>선택: 떡볶이</p>
</body>
</html>
|
- 코드를 실행하고 드롭다운 목록에서 항목을 선택하면 options[index]에서 선택한 option 태그가 출력
- 현재 코드에서는 textContent 속성을 바로 추출해서 사용했는데, option 태그에 다른 속성들을 부여하고 속성을 활용할 수도 있음
- selcet 태그에 multiple 속성을 부여하면 Ctrl 또는 Shift 키를 누르고 여러 항목 선택할 수 있는 상자가 나옴
multiple select 태그 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<select multiple>
<option>떡볶이</option>
<option>순대</option>
<option>오뎅</option>
<option>튀김</option>
</select>
<p></p>
</body>
</html>
|
cm 단위를 여러 단위로 변환하는 프로그램 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
let 현재값
let 변환상수 = 10
const select = document.querySelector('select')
const input = document.querySelector('input')
const span = document.querySelector('span')
const calculate = () => {
span.textContent = (현재값 * 변환상수).toFixed(2)
}
select.addEventListener('change', (event) => {
const options = event.currentTarget.options
const index = event.currentTarget.options.selectedIndex
변환상수 = Number(options[index].value)
calculate()
})
input.addEventListener('keyup', (event) => {
현재값 = Number(event.currentTarget.value)
calculate()
})
})
</script>
</head>
<body>
<input type="text"> cm =
<span></span>
<select>
<option value="10">mm</option>
<option value="0.01">m</option>
<option value="0.393701">inch</option>
</select>
</body>
</html>
|
(2) 체크 박스 활용하기
체크 박스 확용하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<input type="checkbox">
<span>타이머 활성화</span>
<h1></h1>
</body>
</html>
|
(3) 라디오 버튼 활용하기
라디오 버튼 활용하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<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>
|
5) 기본 이벤트 막기
- 웹 브라우저는 이미지에서 마우스 오른쪽 버튼을 클릭하면 다음과 같은 컨텍스트 메뉴를 출력
- 어떤 이벤트가 발생했을 때 웹 브라우저가 기본적으로 처리해주는 것을 기본 이벤트라고 함
- 기본 이벤트를 제거할 때는 event 객체의 preventDefault() 메소드를 사용한다.
이미지 마우스 오른쪽 버튼 클릭 막기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const imgs = document.querySelectorAll('img')
imgs.forEach((img) => {
img.addEventListener('contextmenu', (event) => {
event.preventDefault()
})
})
})
</script>
</head>
<body>
</body>
</html>
|
인터넷에서 이미지 불펌 방지 등을 구현할 때 사용하는 코 |
체크 때만 링크 활성화하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<input type="checkbox">
<span>링크 활성화</span>
<br>
</body>
</html>
|
6) 할 일 목록 만들기 [선택 미션]
할 일 목록 만들기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<h1>할 일 목록</h1>
<input id="todo">
<button id="add-button">추가하기</button>
<div id="todo-list">
</div>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 문서 객체를 가져옵니다.
const input = document.querySelector('#todo')
const todoList = document.querySelector('#todo-list')
const addButton = document.querySelector('#add-button')
// 변수를 선언합니다.
let keyCount = 0
// 함수를 선언합니다.
const addTodo = () => {
// 입력 양식에 내용이 없으면 추가하지 않습니다.
if (input.value.trim() === '') {
alert('할 일을 입력해주세요.')
return
}
// 문서 객체를 설정합니다.
const item = document.createElement('div')
const checkbox = document.createElement('input')
const text = document.createElement('span')
const button = document.createElement('button')
// 문서 객체를 식별할 키를 생성합니다.
const key = keyCount
keyCount += 1
// item 객체를 조작하고 추가합니다.
item.setAttribute('data-key', key)
item.appendChild(checkbox)
item.appendChild(text)
item.appendChild(button)
todoList.appendChild(item)
// checkbox 객체를 조작합니다.
checkbox.type = 'checkbox'
checkbox.addEventListener('change', (event) => {
item.style.textDecoration
= event.target.checked ? 'line-through' : ''
})
// text 객체를 조작합니다.
text.textContent = input.value
// button 객체를 조작합니다.
button.textContent = '제거하기'
button.addEventListener('click', () => {
removeTodo(key)
})
// 입력 양식의 내용을 비웁니다.
input.value = ''
}
const removeTodo = (key) => {
// 식별 키로 문서 객체를 제거합니다.
const item = document.querySelector(`[data-key="${key}"]`)
todoList.removeChild(item)
}
// 이벤트 연결
addButton.addEventListener('click', addTodo)
input.addEventListener('keyup', (event) => {
// 입력 양식에서 Enter 키를 누르면 바로 addTodo() 함수를 호출합니다.
const ENTER = 13
if (event.keyCode === ENTER) {
addTodo()
}
})
})
</script>
</html>
|
7) 타이머로 구현한 남은 글자 수 세기
- 트위트는 다음과 같이 타이머를 사용해서 50밀리초마다 입력 양식 내부의 글자를 확인해서 글자 수를 센다.
- focus 이벤트와 blur 이벤트를 사용
글자 수 출력하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<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>
</head>
<body>
<h1></h1>
<textarea></textarea>
</body>
</html>
|
8) localStorage 객체
- 웹 브라우저가 기본적으로 제공하는 객체
- localStorage.getltem(키): 저장된 값을 추출하고 없으면 undefined가 나옴.
객체의 속성을 추출하는 일반적인 형태로 localStorage.키 또는 localStorage[키] 형태로 사용 - localStorage.setltem(키, 값): 값을 저장
이전과 마찬가지로 객체에 속성을 지정하는 일반적인 형태를 사용할 수도 있음 - localStorage.removeltem(키): 특정 키의 값을 제거
- localStorage.clear(): 저장된 모든 값을 제거
웹 브라우저에 데이터를 저장하는 localStorage 객체와 활용하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
document.addEventListener('DOMContentLoaded', () => {
const p = document.querySelector('p')
const input = document.querySelector('input')
const button = document.querySelector('button')
const savedValue = localStorage.getItem('input')
// localStorage.input도 가능합니다.
if (savedValue) {
input.value = savedValue
p.textContent = `이전 실행 때의 마지막 값: ${savedValue}`
}
input.addEventListener('keyup', (event) => {
const value = event.currentTarget.value
localStorage.setItem('input', value)
// localStorage.input = value도 가능합니다.
})
button.addEventListener('click', (event) => {
localStorage.clear()
input.value = ''
})
})
</script>
</head>
<body>
<p></p>
<button>지우기</button>
<input type="text">
</body>
</html>
|
- localStorage처럼 웹 브라우저가 제공해주는 기능을 웹 API라고 부름
- 책으로도 출판이 별로 안 되어 있는 내용이므로 다음 모질라 문서에서 어떤 API가 있는지 확인해보고
구글 검색 등으로 어떻게 사용하는지 찾아서 공부해야 하는 부분임.
Chap 8 예외 처리
1. 구문 오류와 예외
- 구문 오류(syntex error)
- 괄호 개수를 잘못 입력하는 등의 오류 코드가 실행조차 되지 않는 오류
- 예외(excetion)
- 문법적 오류를 제외하고 코드 실행 중간에 발생하는 오류
- 예외 처리(exception handling)
- 이를 처리하는 것
1) 오류의 종류
- 구문 오류 :: 프로그램 실행 전에 발생하는 오류
- 예외 / 런타임 오류 :: 프로그램 실행 중에 발생하는 오류
(1) 구문 오류
- 괄호의 짝을 맞추지 않았다든지, 문자열을 열었는데 닫지 않았다든지 할 때 발생하는 오류
- 이러한 구문 오류가 있으면 웹 브라우저가 코드를 분석조차 하지 못하므로 실행 되지 않는다.
(2) 예외, 런타임 오류
- 실행 중에 발생하는 오류
- SyntaxError라고 출력되는 오류 이외의 모든 오류(TypeError, ReferenceError, RangeError)
2) 기본 예외 처리
- 조건문을 사용해서 예외가 발생하지 않게 만드는 것
querySelector() 메소드로 추출된 문서 객체가 없는 경우 |
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
const h1 = document.querySelector('h1')
h1.textContent = '안녕하세요'
})
</script>
</html>
|
Uncaught TypeError TypeError: Cannot set properties of null (setting 'textContent') at <anonymous> (c:\예제\chap8\8-1-1.html:12:22) |
기본 예외 처리 |
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
const h1 = document.querySelector('h1')
if (h1) {
h1.textContent = '안녕하세요'
} else {
console.log('h1 태그를 추출할 수 없습니다.')
}
})
</script>
</html>
|
h1 태그를 추출할 수 없습니다. |
3) 고급 예외 처리
- try catch finally 구문을 사용하는 방법
- try catch finally 구문의 기본적인 형태
- try 구문 안에서 예외를 발생하면 이를 catch 구문에서 처리함
- finally 구문은 필수 사항은 아니며 예외 발생 여부와 상관없이 수행해야 하는 작업이 있을 때 사용한다.
- 다음 코드는 변수 willExcept 자체가 존재하지 않는다, willExcept의 byeBye() 메소드를 사용함
- willExcept 객체도 없고 byeBye() 메소드도 존재하지 않는다.
- try 구문 안에서 예외가 발생하면 더 이상 try 구문을 진행하지 않고 catch 구문을 실행한다
try catch 구문의 사용 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
try {
willExcept.byeBye()
console.log("try 구문의 마지막 줄")
} catch (exception) {
console.log("catch 구문의 마지막 줄")
}
</script>
</head>
<body>
</body>
</html>
|
catch 구문의 마지막 줄 |
finally 구문 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
try {
willExcept.byeBye()
console.log("try 구문의 마지막 줄")
} catch (exception) {
console.log("catch 구문의 마지막 줄")
} finally {
console.log("finally 구문의 마지막 줄")
}
</script>
</head>
<body>
</body>
</html>
|
catch 구문의 마지막 줄
finally 구문의 마지막 줄
|
4) finally 구문을 사용하는 이유
예외 처리 구문 내부에서 return 사용하기(1) |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
function test() {
try {
alert('A 위치입니다.')
throw "예외 강제 발생"
} catch (exception) {
alert('B 위치입니다.')
return
}
alert('C 위치입니다.')
}
// 함수를 호출합니다.
test()
</script>
</head>
<body>
</body>
</html>
|
예외 처리 구문 내부에서 return 사용하기(2) |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
function test() {
try {
alert('A 위치입니다.')
throw "예외 강제 발생"
} catch (exception) {
alert('B 위치입니다.')
return
} finally {
alert('C 위치입니다.')
}
}
// 함수를 호출합니다.
test()
</script>
</head>
<body>
</body>
</html>
|
- 예제(1)은 return 키워드를 사용해 함수를 벗어났으므로 "C위치 입니다"를 출력하지 않는다.
- 예제(2)는 3가지 모두 출력 => finally 구문을 반드시 실행한다.
- 이처럼 다음과 같은 경우에 결과가 달라짐
- try catch 구문 내부에서 return 키워드를 만날 때
- try catch 구문 내부에서 break 또는 continue 키워드를 만날 때
2. 예외 처리 고급
- 예외 객체(exception object)
- 예외가 발생하면 예외와 발생된 정보를 확인할 수 있는 것
- 개발자가 예외를 강제로 발생시켜줘야 하는 경우가 많다.
- 예외를 강제로 발생시킬 때 throw 키워드를 사
1) 예외 객체
- try catch 구문을 사용할 때 catch의 괄호 안에 입력하는 식별자가 예외 객체
- 아무 식별자나 입력해도 괜찮지만, 일반적으로 e나 exception이라는 식별자를 사용!
속성 이름 | 설명 |
name | 예외 이름 |
message | 예외 메지지 |
예외 정보 출력하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
try {
const array = new Array(999999999999999)
} catch (exception) {
console.log(exception)
console.log()
console.log(`예외 이름: ${exception.name}`)
console.log(`예외 메시지: ${exception.message}`)
}
</script>
</head>
<body>
</body>
</html>
|
2) 예외 강제 발생
- 상황에 따라서 예외를 강제로 발생시켜야 하는 경우도 있음
- 예외를 강제로 발생시킬 때는 throw 키워드를 사용
- throw 구문은 다음과 같은 형태로 사용
예외 강제로 발생시키고 잡기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
function divide(a, b) {
if (b === 0) {
throw '0으로는 나눌 수 없습니다.'
}
return a / b
}
console.log(divide(10, 2))
console.log(divide(10, 0))
</script>
</head>
<body>
</body>
</html>
|
예외를 강제로 발생시키기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
function test(object) {
console.log(object.a + object.b)
}
test({})
</script>
</head>
<body>
</body>
</html>
|
NaN |
- 일반적인 프로그래밍 언어라면,
- Object 객체에 a 속성과 b 속성이 없으므로 예외를 발생할 것이고,
- 존재하지 않는 것을 더하므로 object.a + object.b를 할 때도 예외를 발생
- 그러면 사용자는 자신이 잘못 사용했다는 것을 인지하고 수정할 수 있음
- 하지만 자바스크립트는,
- object.a가 undefined로 나오며, object.b도 undefined로 나옴
- 여기에서 undefined + undefined를 하면 NaN이 나옴
- 즉, 아무 오류 없이 코드가 정상적으로 실행
- 자바스크립트는 undefined와 NaN이라는 값이 있어서 다른 프로그래밍 언어에 비해서 예외를 적게 발생시
- 사용자에게 함수를 잘못 사용했다는 것을 강제로라도 인지시켜줄 필요가 있다.
예외를 강제로 발생시켜서 사용 유도하기 |
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
function test(object) {
if (object.a !== undefined && object.b !== undefined) {
console.log(object.a + object.b)
} else {
throw new Error("a 속성과 b 속성을 지정하지 않았습니다.")
}
}
test({})
</script>
</head>
<body>
</body>
</html>
|
728x90
반응형
'혼공 스터디 > 혼자 공부하는 자바스크립트' 카테고리의 다른 글
[혼공스] 5주차 : 객체 (0) | 2024.02.04 |
---|---|
[ 혼공스 ] 4주차 : 함수 (0) | 2024.01.26 |
[ 혼공스 ] 3주차 : 반복문 (0) | 2024.01.20 |
[ 혼공스 ] 2주차 : 조건문 (0) | 2024.01.14 |
[ 혼공스 ] 1주차 (1) | 2024.01.07 |