문서 객체? HTML 에서의 요소들 (html, head, body, title, h1, div, span 등)
문서 객체 모델 Document Objects Model : 문서 객체를 조합해서 만든 전체적인 형태
웹 브라우저가 문서 객체를 모두 읽고 나서 실행하는 이벤트
코드를 입력할 때 DOMContentLoaded 문자열은 오탈자를 입력해도 오류를 발생시키지 않음!
document.addEventListener('DOMContentLoaded', () =>{
//문장
})
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta num="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
//DOMContentLoaded 이벤트 만들기
document.addEventListener('DOMContentLoaded', () => { //이벤트가 완료되면 (HTML 문서가 로드 완료되면), 화살표 함수 내의 지정된 함수가 실행됨
//text 라는 매개변수를 받아 이를 포함한 <h1> 요소를 포함하는 HTML 문자열을 반환하는 `h1`라는 함수 정의
const h1 = (text) => `<h1>${text}</h1>`
//h1 함수가 반환한 'DOMContentLoaded 이벤트 발생'을 가져와 HTML 문서의 <body> 요소에 내용을 추가
document.body.innerHTML += h1('DOMContentLoaded 이벤트 발생')
})
</script>
</head>
<body>
</body>
</html>
document.head
document.body
document.title
//head와 body 요소 내부에 만든 다른 요소들
document.querySelector(선택자)
document.querySelectorAll(선택자)
querySelector() | querySelectorAll() |
---|---|
요소 하나만 추출 | 문서 객체를 여러 개 추출 |
querySelector()
document.addEventListener('DOMContentLoaded', () =>{
//요소를 읽어들임
const header = document.querySelector('h1') //h1 태그 이름으로 요소 선택
//텍스트와 스타일 변경
header.textContent = 'HEADERS'
header.style.color = 'white'
header.style.backgroundColor = 'black'
header.style.padding = '10px'
})
querySelectorAll()
문서 객체 여러 개를 배열로 읽어들이는 함수이기에 내부의 요소에 접근하고 활용하려면 반복을 돌려야 함 ⇒ 일반적으로 forEach()
사용
document.addEventListener('DOMContentLoaded', () =>{
//요소를 읽어들임
const headers = document.querySelectorAll('h1') //h1 태그 이름으로 요소 선택
//텍스트와 스타일 변경
headers.forEach((header) => {
header.textContent = 'HEADERS'
header.style.color = 'white'
header.style.backgroundColor = 'black'
header.style.padding = '10px'
})
})
속성 이름 | 설명 |
---|---|
문서 객체.textContent | 입력된 문자열을 그대로 넣음 |
문서 객체.innerHTML | 입력된 문자열을 HTML 형식으로 넣음 |
document.addEventListener('DOMContentLoaded', () =>{
const a = document.querySelector('#a')
const b = document.querySelector('#b') //특정 아이디로 요소 선택
a.textContent = '<h1>textContent 속성</h1>'
b.innerHTML = '<h1>innerHTML 속성</h1>'
})
textContent vs InnerContent
textContent는 최신 웹 브라우저에서 사용, 성능이 좋으므로 웬만하면 textContent 사용
속성 이름 | 설명 |
---|---|
문서 객체.setAttribute(속성 이름, 값) | 특정 속성에 값을 지정 |
문서 객체.getAttribute(속성 이름) | 특정 속성을 추출 |
document.addEventListener('DOMContentLoaded', () =>{
const rects = document.querySelectorAll('.rect') //클래스
rects.forEach((rect, index) => {
const width = (index + 1) * 100 //index 깂은 [0,1,2,3]이 반복됨 1을 더해서 [1,2,3,4]가 되게, 100 곱해서 [100,200,300,400]이 되게
const src = `http://placekitten.com/${width}/250`
rect.setAttribute('src', src) //src 값에 속성 지정
})
})
속성들의 이름이 CSS 와 조금 다름 (캐멀 케이스 사용하여 표현)
CSS 속성 이름 | 자바스크립트 style 속성 이름 |
---|---|
background-color | backgroundColor |
text-align | textAlign |
font-size | fontSize |
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta num="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script defer src="main.js"></script>
</head>
<body>
<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>
//스타일 조작하기
document.addEventListener('DOMContentLoaded', () => {
const divs = document.querySelectorAll('body > div') //body 태그 아래의 div 선택
divs.forEach((div, index) => { //div 개수만큼 반복하여 출력하기
console.log(div, index)
const val = index * 10
div.style.height = `10px`
div.style.backgroundColor = `rgba(${val}, ${val}, ${val} )`
})
})
document.createElement(문서 객체 이름)
문서 객체를 만들었다고 문서 객체가 배치되는 것은 아님 ⇒ 어떤 문서 아래에 추가할지 지정해야 함
부모 객체.appendChild(자식 객체 )
//h1 태그 생성하고 document.body 태그에 추가하는 코드
document.addEventListener('DOMContentLoaded', () =>{
//문서 객체 생성하기
const header = document.createElement('h1') //h1 태그 생성
//생성한 태그 조작하기
header.textContent = '문서 객체 동적으로 생성하기'
header.setAttribute('data-custom', '사용자 정의 속성')
header.style.color = 'white'
header.style.backgroundColor = 'black'
//h1 태그를 body 태그 아래에 추가
**document.body.appendChild(header)**
})
부모 객체.appendChild(자식 객체)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta num="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script defer src="main.js"></script>
</head>
<body>
<div id = 'first'>
<h1>첫 번째 div 태그 내부</h1>
</div>
<hr>
<div id = 'second'>
<h1>두 번째 div 태그 내부</h1>
</div>
</body>
</html>
//문서 객체 이동하기
document.addEventListener('DOMContentLoaded', () =>{
//문서 객체 읽어들이고 생성하기
const div1 = document.querySelector('#first') //id 속성이 first인 div 태그를 선택
const div2 = document.querySelector('#second') //id 속성이 second인 div 태그를 선택
const h1 = document.createElement('h1') //h1 태그 생성
h1.textContent = '이동하는 h1 태그'
//서로 번갈아가면서 실행하는 함수 구현
const toFirst = () => {
**div1.appendChild(h1) //h1을 div1에 추가**
setTimeout(toSecond, 1000) //1초 뒤에 toSecond 함수를 실행
}
const toSecond = () => {
**div2.appendChild(h1) //h1을 div2에 추가**
setTimeout(toFirst, 10000) //10초 뒤에 toFirst 함수를 실행
}
toFirst()
})
부모 객체.removeChild(자식 객체)
appendChild() 등으로 부모 객체와 이미 연결이 완료된 문서 객체의 경우
⇒문서 객체.parentNode.removeChild(문서 객체)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta num="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script defer src="main.js"></script>
</head>
<body>
<hr>
<h1>제거 대상 문거 객체</h1>
<hr>
</body>
</html>
//문서 객체 제거하기
document.addEventListener('DOMContentLoaded', ()=>{
setTimeout(() => {
const h1 = document.querySelector('h1')
h1.parentNode.removeChild(h1) //h1 태그의 부모 객체인 body에 접근하여 제거
//document.body.removeChild(h1) 이렇게도 가능함
}, 3000); //3초 뒤
})
문서 객체.addEventListener(이벤트 이름, 콜백 함수)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta num="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script defer src="main.js"></script>
<style>
h1 {
user-select: none; /*클릭 여러번 했을 때 글자가 선택되는 걸 막기 위한 스타일*/
}
</style>
</head>
<body>
<h1>클릭 횟수 : 0</h1>
</body>
</html>
//h1 클릭할 때 이벤트 리스너(콜백 함수)를 호출하는 예
**document.addEventListener('DOMContentLoaded', () => {**
let count = 0
const h1 = document.querySelector('h1')
**document.addEventListener('click', () =>{**
count++
h1.textContent = `클릭 횟수 : ${count}`
})
})
문서 객체.removeEventListener(이벤트 이름, 이벤트 리스너)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta num="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script defer src="main.js"></script>
<style>
h1 {
user-select: none; /*클릭 여러번 했을 때 글자가 선택되는 걸 막기 위한 스타일*/
}
</style>
</head>
<body>
<h1>클릭 횟수 : 0</h1>
<button id = 'connect'>이벤트 연결</button>
<button id = 'disconnect'>이벤트 제거</button>
<p>이벤트 연결 상태 : 해제</p>
</body>
</html>
//이벤트 연결 제거하기
document.addEventListener('DOMContentLoaded', () => {
let count = 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 = `클릭 횟수 : ${count++}`
}
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
}
})
})
const headerElementById1 = document.querySelector('#header');
const headerElementById2 = document.getElementById('header');
const activeSpanByClass1 = document.querySelector('.active');
const activeSpanByClass2 = document.getElementsByClassName('active')[0];
const nameInputById1 = document.querySelector('#name-input');
const nameInputById2 = document.getElementById('name-input');
= 이벤트를 연결하는 방법
표준 이벤트 모델
addEventListener()
고전 이벤트 모델
document.body.on~~ = (event) ⇒ { }
이벤트 리스너를 1개만 연결 가능
인라인 이벤트 모델
고전 이벤트 모델처럼 on~~으로 시작하는 속성을 HTML 요소에 직접 넣어서 이벤트를 연결하는 것
<script>
const listener = (event) => {
}
</script>
<body on~~="listener(event)">
</body>
이벤트 | 설명 |
---|---|
keydown | 키가 눌릴 때 실행 |
keypress | 키가 입력 되었을 때 실행 |
keyup | 키보드에서 키가 떨어질 때 실행 (주사용) |
<body>
<h1></h1>
<textarea></textarea>
</body>
//남은 글자 수 출력
document.addEventListener('DOMContentLoaded', () => {
const textarea = document.querySelector('textarea')
const h1 = document.querySelector('h1')
textarea.addEventListener('**keyup**', (event) => {
const length = textarea.value.length //value 속성으로 입력 양식의 글자들을 읽어들일 수 있음
h1.textContent = `글자 수 : ${length}`
})
})
keydown, keypress, keyup 모두 오류가 날 수 있음 ㅠ
이벤트 속성 이름 | 설명 |
---|---|
code | 입력한 키 |
keyCode | 입력한 키를 나타내는 숫자 |
altKey | alt 키를 눌렀는지 |
ctrlKey | ctrl 키를 눌렀는지 |
shiftKey | shift 키를 눌렀는지 |
//키보드의 이벤트와 관련된 속성
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.code 출력, undefined라면 event.keyCode 출력
event.code : event.keyCode}<br>`
h1.innerHTML = output
}
document.addEventListener('keydown', print) //키가 눌릴 때 출력
document.addEventListener('keyup', print) //키가 떨어질 때 출력
})
//키보드의 이벤트와 관련된 속성
document.addEventListener('DOMContentLoaded', () => {
//별 초기 설정
const star= document.querySelector('h1')
star.style.position = 'absolute' //position 값 설정
//별의 이동을 출력하는 기능
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()
})
})
eventCurrentTarget | this |
---|---|
화살표 함수, function() {} | function() {} |
eventCurrentTarget
this
<body>
<input type="text">inch<br>
<button>계산</button>
<p></p>
</body>
//inch -> cm
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`
})
})
조기 리턴
ex) isNan() 함수의 결과가 true로 나오는 숫자가 아닌 경우 바로 return 키워드로 리턴해서 이후 코드를 실행 X
<body>
<input type="text">
<p></p>
</body>
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}`
}
})
})
select
<body>
<select>
<option>떡볶이</option>
<option>순대</option>
<option>오뎅</option>
<option>튀김</option>
</select>
<p>선택 : 떡복이 </p>
<!-- 처음에 떡볶이가 선택되어 있도록 초기값 지정 -->
</body>
//select 태그
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}` //선택한 option 태그를 추출
})
})
multiple select
<body>
<select multiple>
<option>떡볶이</option>
<option>순대</option>
<option>오뎅</option>
<option>튀김</option>
</select>
<p></p>
</body>
//multiple select
document.addEventListener('DOMContentLoaded', () => {
const select = document.querySelector('select')
const p = document.querySelector('p')
select.addEventListener('change', (event) => {
const options = event.currentTarget.options
const list = []
//options 속성에는 forEach 메소드가 없어서 반복문으로 돌려야 함
for (const option of options){
//select 속성 확인
if (option.selected){
list.push(option.textContent)
}
}
})
})
<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>
//cm 단위를 여러 단위로 변환하는 프로그램
document.addEventListener('DOMContentLoaded', ()=> {
let 현재값
let 변환상수 = 10
const select = document.querySelector('select')
const input = document.querySelector('input')
const span = document.querySelector('span')
const cal = () => {
span.textContent = (현재값 * 변환상수).toFixed(2) //소수점 2번째 자리까지 출력하기
}
select.addEventListener('change', (event) => {
const options = event.currentTarget.options
const index = event.currentTarget.options.selectedIndex
변환상수 = Number(options[index].value) //항목 선택시 항목의 value 속성을 추출
cal()
})
input.addEventListener('keyup', (event) => {
현재값 = Number(event.currentTarget.value) //값을 입력하면 현재 값을 출력함
cal()
})
})
checked
일반적인 웹 페이지에서 약관 읽었는지, SMS 수신 허가, 이메일 수신 허가 등
<body>
<input type="checkbox">
<span>타이머 활성화</span>
<h1></h1>
</body>
//체크 박스 활용하기
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) //1초 후부터
}
else {
//체크 X
clearInterval(timerId)
}
})
})
<body>
<input type="checkbox">
<span>타이머 활성화</span>
<h1></h1>
</body>
//체크 박스 활용하기
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 += 0.1**
h1.textContent = `${(timer).**toFixed(1)**}초`
}, **100) //0.1초 후부터**
}
else {
//체크 X
clearInterval(timerId)
}
})
})
checked
여러 개 중 하나 선택할 때
<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>
//라디오 버튼 활용
document.addEventListener('DOMContentLoaded', ()=>{
//문서 객체 추출
const output = document.querySelector('#output') //id니까 #
const radios = document.querySelectorAll('[name=pet]')
//모든 라디오 버튼에
radios.forEach((radio) => {
//이벤트 연결
radio.addEventListener('change', (event) => {
const current = event.currentTarget
if (current.checked) {
output.textContent = `좋아하는 애완동물은 ${current.value}이시군요!`
}
})
});
})
preventDefault()
<body>
<img src="http://placekitten.com/300/300" alt="">
</body>
//이미지 오른쪽 마우스 버튼 막기
document.addEventListener('DOMContentLoaded', () => {
const imgs = document.querySelectorAll('img')
imgs.forEach((img)=> {
img.addEventListener('contextmenu', (event) => {
event.preventDefault() //컨텍스트 메뉴를 출력하는 기본 이벤트를 제거
})
}
)
})
<body>
<input type="checkbox">
<span>링크 활성화</span>
<br>
<a href="https://chat.openai.com/">ChatGPT</a>
</body>
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()
}
})
})
<body>
<h1>할 일 목록</h1>
<input id="todo">
<button id="add-button">추가하기</button>
<div id="todo-list"></div>
</body>
document.addEventListener('DOMContentLoaded',() => {
//문서 객체 가져오기
const input = document.querySelector('#todo')
const todoList = document.querySelector('#todo-list')
const addButton = document.querySelector('#add-button')
//변수 선언
let keyCount = 0 //removeTodo()에서 문서 객체 쉽게 제거하려고
//함수 선언
const addTodo = () =>{
//입력 양식에 내용이 없으면 추가하지 x
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')
//문서 객체를 식별할 키를 생성, 이후 removeTodo()에서 문서 객체 쉽게 제거하려고
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()
}
})
})
addEventListener
인라인 이벤트 모델 : <body onload = “listener()”…
고전 이벤트 모델 : document.body.onload = listener
event.currentTarget
this