1. 문서 객체 모델 이해
문서 객체 모델 생성되는 방식/ 노드 타입 살펴보기
웹 브라우저: 문서 객체 모델(DOM) 생성할 수 있음
문서 객체 모델: 웹 브라우저에 표시되는 HTML 문서 구조를 객체화한 모델 구조
생성한 문서 객체 모델 ~> HTML 문서의 구성 요소를 객체로 인식
문서 객체 모델이 생성되는 방식
문서 객체 모델: 웹 브라우저) HTML 문서 해석 -> 객체로 변환 -> 웹 브라우저에 표시
=> 웹 브라우저에 표시되는 HTML 문서는 내부적으로 문서 객체 모델을 해석해서 보이게 됨
- DOM 트리: 트리(tree) 구조 가짐
- 노드(node): document 객체 하위에 HTML 태그 요소, 속성, 텍스트, 주석 등 트리 형태로 구성
-> 부모, 자식, 형제 관계 형성 - 루트 노드(root node): DOM 트리의 가장 꼭대기(최상위)에 있는 노드(ex. html/ document - 객체)
- 노드(node): document 객체 하위에 HTML 태그 요소, 속성, 텍스트, 주석 등 트리 형태로 구성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document Object Model</title>
</head>
<body>
<h1>header</h1>
<a href="#">link</a>
</body>
</html>
노드 타입 살펴보기
문서 객체 모델은 CSS 포함 X => CSS와 관련 있는 노드 타입 X
- 문서 노드(Node.DOCUMENT_NODE): 최상위 document 객체
- 요소 노드(Node.ELEMENT_NODE): h1, p 태그와 같은 요소
- 속성 노드(Node.ATTRIBUTE_NODE): href, src와 같은 속성
- 텍스트 노드(Node.TEXT_NODE): 텍스트
- 주석 노드(Node.COMMENT_NODE): 주석
2. 노드 선택
속성/ 메서드
자바스크립트로 웹 브라우저에 표시되는 HTML 문서 조작 -> 문서 객체 모델 조작
=> window 객체의 document 객체 사용해 조작할 수 있음(조작하려는 문서 객체 모델의 노드 선택)
속성
- (+) 노드 타입 가리지 X 모든 노드 이동하며 선택할 수 있음
- (-) DOM 트리가 복잡할수록 원하는 노드 찾아가기 어려움
모든 노드 탐색 | parentNode | 부모 노드를 반환 |
childNodes | 모든 자식 노드를 반환 | |
firstChild | 첫 번째 자식 노드를 반환 | |
lastChild | 마지막 자식 노드를 반환 | |
previousSibling | 이전 형제 노드를 반환 | |
nextSibling | 다음 형제 노드를 반환 | |
요소 노드 탐색 | parentElement | 부모 요소 노드를 반환 |
children | 자식 요소 노드를 반환 | |
firstElementChild | 첫 번째 자식 요소 노드를 반환 | |
lastElementChild | 마지막 자식 요소 노드를 반환 | |
previousElementSibling | 이전 요소 노드를 반환 | |
nextElementSibling | 다음 요소 노드를 반환 |
// document 객체로 접근할 수 있는 html 노드로 이동 -> firstChild 속성
document.firstChild; // <DOCTYPE html>
// 첫 번째 자식 요소 노드로 이동 -> firstElementChild
document.firstElementChild; // html
// 연속으로 사용
document.childNodes[1].firstElementChild.firstElementChild.nextElementSibling;
메서드
속성값과 태그명 사용 - get 메서드
- getElementById(<id 속성값>)
- id 속성값과 일치하는 요소 노드를 1개만 선택
- 해당하는 요소 하나만 보여 줌
- getElementsByClassName(<class 속성값>)
- class 속성값과 일치하는 요소 노드를 모두 선택
- *HTMLCollection 객체로 여러 요소 한꺼번에 선택
- getElemenetsByTagName(<태그명>)
- 태그명과 일치하는 요소 노드를 모두 선택
- *HTMLCollection 객체로 여러 요소 한꺼번에 선택
*HTMLCollection 객체: 유사 배열 -> 배열의 인덱스로 요소에 하나씩 접근 가능
<script>
// id 속성값이 title인 요소 노드 1개 선택하기
const el = document.getElementById("title");
console.log(el);
// class 속성값이 text인 요소 노드 모두 선택하기
const classEl = document.getElementsByClassName("text");
console.log(classEl);
console.log(classEl[0]);
console.log(classEl[1]);
// p 태그에 해당하는 요소 노드 모두 선택하기
const tagEls = document.getElementsByName("p");
console.log(tagEls);
console.log(tagEls[0]);
console.log(tagEls[1]);
</script>
CSS 선택자 사용 - query 메서드
- querySelector(<CSS 선택자>)
- 매개변수로 넘어오는 CSS 선택자에 해당하는 노드를 1개만 선택
- querySelectorAll(<CSS 선택자>)
- 매개변수로 넘어오는 CSS 선택자에 해당하는 노드를 모두 선택
- NodeList 객체에 담아 반환
<body>
<div class="box-1">
<p class="text">text-1</p>
<p class="text">text-2</p>
</div>
<div class="box-2">
<p class="text">text-3</p>
<p class="text">text-4</p>
</div>
</body>
<script>
// class 속성값이 box-1인 요소 노드 선택
const el = document.querySelector(".box-1");
// class 속성값이 box-1인 요소의 하위에 있는 p 태그
const el = document.getElementsByClassName("box-1")[0].children; // HTMLCollection 객체
const el = document.querySelectorAll(".box-1 .text"); // NodeList 객체
</script>
3. 노드 조작
콘텐츠/ 스타일/ 클래스/ 데이터/ 메서드
콘텐츠
- textContent
- 요소 노드의 모든 텍스트에 접근
- 단순히 텍스트로 취급 -> 그대로 노드의 콘텐츠에 넣음
- innerText
- 요소 노드의 텍스트 중 웹 브라우저에 표시되는 텍스트에만 접근
- 태그로 인식해 노드의 콘텐츠에 적용
- innerHTML
- 요소 노드의 텍스트 중 HTML 태그를 포함한 텍스트에만 접근
- 단순히 텍스트로 취급 -> 그대로 노드의 콘텐츠에 넣음
<p id="title">Hello, <span style="display:none;">Javascript!</span></p>
<script>
document.getElementById("title").textContent; // Hello, Javascript!
document.getElementById("title").innerText; // Hello,
document.getElementById("title").innerHTML; // Hello, <span style="display: none;">Javascript!</span>
</script>
<p id="textContent"></p>
<p id="innerText"></p>
<p id="innerHTML"></p>
<script>
document.querySelector("#textContent").textContent = `<strong>textContent</strong> 속성`;
document.querySelector("#innerText").innerText = `<strong>innerText</strong> 속성`;
document.querySelector("#innerHTML").innerHTML = `<strong>innerHTML</strong> 속성`;
</script>
- innerHTML 속성에 값 할당 -> 태그로 인식해 노드의 콘텐츠에 적용
- But, textContent 속성, innerText 속성 -> 단순히 텍스트로 취급 => 값을 그대로 노드의 콘텐츠에 넣음
스타일
- <노드>.style.<css 속성명> = <속성값>;
- querySelector() 메서드: 스타일 조작하고 싶은 노드 선택
- 선택한 노드에 style 속성으로 조작하고 싶은 CSS 속성명 적고, 적용하고 싶은 CSS 속성값 할당
- 카멜 표기법 사용 ex. background-color -> backgroundColor
<p id="text">text</p>
<script>
const pEl = document.querySelector("p"); // 노드 선택하기
pEl.style.backgroundColor = "#ff0000";
pEl.style.fontSize = "20px";
pEl.style.color = "#ffffff";
</script>
클래스
- <노드>.classList.add("class 속성값"); // 추가
- <노드>.classList.remove("class 속성값"); // 삭제
- <노드>.classList.toggle("class 속성값"); // 추가와 삭제 반
<style>
.red-color{
color:red;
}
.fz20{
font-size:20px;
}
</style>
(중략)
<p id="text">text</p>
<script>
const pEl = document.querySelector("#text"); // 노드 선택하기
pEl.classList.add("red-color");
pEl.classList.add("fz20");
</script>
데이터
data-* 속성
- 사용자 정의(custom) 속성
- HTML 문법에서 사용 O 속성 외에 사용자가 원하는 속성을 추가할 수 있음
- 자바스크립트의 dataset 속성 사용해 조작
<button data-cnt="10">가방 구매</button>
<button data-cnt="0">신발 구매</button>
<script>
// querySelectorAll() 메서드: 복수의 노드 선택
const buttonEls = document.querySelectorAll("button");
// forEach() 메서드: 반복해서 각 노드에 접근
buttonEls.forEach((el) => {
// dataset 속성으로 data-cnt 속성 정보 가져와 출력
console.log(el.dataset);
console.log(el.dataset.cnt);
})
</script>
// 실행결과
/* dataset 속성으로 노드의 data-* 속성에 대한 정보 가져옴,
정보 -> DOMStringMap 객체에 담겨 반환 */
// 객체 속성에 접근 -> 정확하게 data-cnt 속성 값만 가져옴
메서드
모든 속성을 전체적으로 조작
- <노드>.getAttribute("속성명");
- 속성값 가져옴
- 모든 속성의 상위 메서드 -> classList 속성이나 dataset 속성으로 하는 조작 할 수 O
- <노드>.setAttribute("속성명", "속성값");
- 속성값 설정
- 모든 속성의 상위 메서드 -> classList 속성이나 dataset 속성으로 하는 조작 할 수 O
- <노드>.removeAttribute("속성명");
- 속성 삭제
<a href="https://www.gilbut.co.kr">길벗</a>
<script>
// querySelector() 메서드: a 태그에 해당하는 요소 노드 선택
const aEl = document.querySelector("a");
// getAttribute() 메서드: href 속성값 가져옴
const href = aEl.getAttribute("href");
// setAttribute() 메서드: 속성값 새로 설정
aEl.setAttribute("href", "https://www.sucoding.kr");
aEl.innerText = "수코딩";
// 속성값 적용해 새 창으로 열리게
aEl.setAttribute("target", "_blank");
</script>
*classList 속성과 setAttribute() 메서드
classList 속성으로 class 속성값 추가/삭제 -> 기존 요소가 가지고 있던 class 속성값을 보존하면서 추가/삭제
=> 이미 class 속성 O -> 단순히 추가되는 형태
But, setAttribute() 메서드: 아예 속성값 새로 설정 => 기존 class 속성값 보존 X
4. 노드 추가/ 삭제
노드 추가/ 삭제
노드 추가
노드 생성 | createElement() | 요소 노드 생성 |
createTextNode() | 텍스트 노드 생성 | |
createAttribute() | 속성 노드 생성 | |
노드 연결 | <기준 노드>.appendChild(<자식 노드>) | 기준 노드에 자식 노드 연결 |
<기준 노드>.setAttributeNode(<속성 노드>) | 기준 노드에 속성 노드 연결 |
<!DOCTYPE html>
<html>
<head>
<title>Create Node</title>
</head>
<body>
<script>
// 요소 노드 생성
// 요소 노드: 주축이 되는 노드
const aEl = document.createElement("a");
// appendChild() 메서드 ~> 생성된 노드 -> 기존 DOM 트리와 연결
document.body.appendChild(aEl);
// 텍스트 노드 추가
const txtEl = document.createTextNode("길벗");
document.querySelector("a").appendChild(txtEl);
// href 속성 노드 추가
const hrefAttr = document.createAttribute("href");
hrefAttr.value = "https://www.gilbut.co.kr";
// a 요소 노드의 자식 노드로 추가 X
document.querySelector("a").setAttributeNode(hrefAttr);
</script>
</body>
</html>
노드 삭제
<부모 노드>.removeChild(<자식 노드>)
// p 요소 노드 찾아서 삭제
<body>
<p>text 1</p>
<a href="https://www.gilbut.co.kr">길벗</a>
<a href="https://www.sucoding.kr">수코딩</a>
<script>
const pEl = document.querySelector("p");
pEl.parentNode.removeChild(pEl);
</script>
</body>
// DOM 트리 순회하면서, a 태그에 해당하는 요소 노드 모두 삭제
<body>
<p>text 1</p>
<a href="https://www.gilbut.co.kr">길벗</a>
<a href="https://www.sucoding.kr">수코딩</a>
<script>
const childNodes = document.body.childNodes;
childNodes.forEach((node) => {
if(node.nodeName === "a")
node.parentNode.removeChild(node);
})
</script>
</body>
5. 폼(form) 조작
form 태그 선택하기/ 폼 요소 선택하기/ 폼 요소의 입력값 다루기
form 태그 선택하기
- forms 속성
- document 객체의 forms 속성 -> 모든 form 태그의 노드 정보를 HTMLCollection 객체에 담아 반환
- => (+) 화면에 있는 form 요소 노드 쉽게 선택할 수 있음
- (HTMLCollection 객체: 유사 배열 -> 인덱스 ~> form 요소 노드에 하나씩 접근 O)
- (-) form 태그의 위치 변경 -> 잘못 참조 => 오류 발
- name 속성
- (+) 직관적으로 form 요소 노드 선택할 수 있음
- (+) form 태그 순서 변경 상관 X
폼 요소 선택하기
- elements 속성
- form 요소 노드의 하위 노드 중 폼 요소 노드만 반환하는 속성
- HTMLFormControlsCollection 객체에 여러 개의 노드 담아 반환
HTMLFormControlsCollection 객체: form 요소 노드의 하위에 있는 폼 요소 노드의 정보 담겨 있음
- name 속성
- name 속성값으로 노드 참조할 수 있게 데이터 정의
=> 폼 요소에 접근: 인덱스/ name 속성값
<body>
<form name="frm1">
<label for="uname">이름</label>
<input type="text" id="uname" name="uname">
<label for="age">나이</label>
<input type="text" id="age" name="age">
<label for="gender">성별</label>
<select id="gender" name="gender">
<option value="male">male</option>
<option value="female">female</option>
</select>
<button type="submit">전송</button>
</form>
</body>
document.frm1.elements[0]; // 0번 인덱스 노드
document.frm1.elements['uname']; // form 요소 노드의 하위 노드 중 name 속성값이 uname인 노드
// elements 속성 생략하고 name 속성값으로 바로 접근
document.frm1.uname;
document.forms[0].gender;
폼 요소의 입력값 다루기
- 한 줄 입력 요소 다루기
- input 태그의 type 속성값: text, password, number, url, search, email 등
- value 속성: 사용자가 입력한 값 가져오기
- 여러 줄 입력 요소 다루기
- textarea 태그
// 한 줄
<form name="frm">
<input type="text" name="id">
<input type="password" name="pw">
</form>
<script>
document.frm.id.value = 'jscoding';
document.frm.pw.value = 'aaaccc';
</script>
// 여러 줄
<form name="frm">
<textarea name="desc"></textarea>
</form>
<script>
document.frm.desc.value = 'setting!';
</script>
- 체크박스
- checked 속성: 체크 표시 있는지 확인
- 체크된 상태 -> checked 속성에 true를 할당
- value 속성: 값 가져옴
- checked 속성: 체크 표시 있는지 확인
- 라디오버튼
- 여러 개의 항목 중 하나만 선택하게 할 때 사용하는 폼 요소
- checked 속성: 선택됐는지 확인
- value 속성: 값 가져옴
- 콤보박스
- select 태그
- 여러 항목에서 하나를 선택하는 형태의 폼 요소
- selected 속성: 선택 항목 확인
- value 속성: 값 가져옴
- 파일 업로드 요소
- <input type="file" name=upload">
- files 속성으로 반환되는 FileList 객체
const files = document.frm.upload.files;
files[0].name; // 파일 이름
files[0].size; // 파일 크기
files[0].type; // 파일 타입
files[0].lastModifiedDate; // 파일 마지막 수정일
*폼 요소 관련 기타 메서드
- submit(): 폼 요소의 값을 전송(submit)
- focus(): 폼 요소에 포커스(커서)를 이동
6. 이벤트(event) 다루기
이벤트 종류/ 이벤트 등록
이벤트: 웹 브라우저와 사용자 사이에 상호작용이 발생하는 특정 시점
이벤트 종류
마우스 이벤트 | onclick | 마우스로 클릭하면 발생 |
ondblclick | 마우스로 빠르게 두 번 클릭하면 발생 | |
onmouseover | 마우스 포인터를 올리면 발생 | |
onmouseout | 마우스 포인터가 빠져나가면 발생 | |
onmousemove | 마우스 포인터가 움직이면 발생 | |
onwheel | 마우스 휠(wheel)을 움직이면 발생 | |
키보드 이벤트 | onkeypress | 키보드 버튼을 누르고 있는 동안 발생 |
onkeydown | 키보드 버튼을 누른 순간 발생 | |
onkeyup | 키보드 버튼을 눌렀다가 뗀 순간 발생 | |
포커스 이벤트 | onfocus | 요소에 포커스가 되면 발생 |
onblur | 요소가 포커스를 잃으면 발생 | |
폼 이벤트 | onsubmit | 폼이 전송될 때 발생 |
리소스 이벤트 | onload | 웹 브라우저의 리소스 로드가 끝나면 발생 |
이벤트 등록
이벤트가 발생할 때 어떤 작업을 할지 자바스크립트 코드로 작성하는 것
인라인
- HTML 태그에 속성으로 이벤트를 등록하는 방법
// 입력창 클릭 -> 커서 활성화 => onfocus 이벤트 발생
// 입력창 외부 영역 클릭 -> onblur 이벤트 발생 => 블러(focus out) 상태
<form>
<input type="text" onfocus="focusEvent()" onblur="blurEvent()">
</form>
<script>
function focusEvent(){
console.log("focus on");
}
function blurEvent(){
console.log("focus out");
}
</script>
* 포커스 이벤트 사용 시 주의할 점
코드 내부에 경고창 나타내는 alert() 메서드 사용 X (경고창 무한)
- 경고창 클릭 -> 입력창에서 커서 빠져나갔다고 판단 => onblur 이벤트 발생
- 경고창 닫히면서 커서 다시 입력창 들어가서 onfocus 이벤트 발생
프로퍼티 리스너(property listener)
- 요소 노드에 직접 속성으로 이벤트를 등록하는 방법
<button>클릭</button>
<script>
const btnEl = document.querySelector("button");
btnEl.onclick = function(){
alert("click");
}
// 화살표 함수
btnEl.onclick = () => {
alert('arrow click');
}
// 함수 별도 정의, 함수명 이용 -> 이벤트와 연결
btnEl.onclick = clickEvent;
function clickEvent(){
alert('click');
}
</script>
이벤트 등록 메서드
- DOM에서 제공하는 addEventListener() 메서드 사용
- <노드>.addEventListener("<이벤트 타입>", <이벤트 함수>);
<button>클릭</button>
<script>
const btnEl = document.querySelector("button");
btnEl.addEventListener("click", function(){
alert("button Click");
});
// 화살표 함수 or 함수 선언문이나 함수 표현식으로 정의한 함수명으로 연결
// 함수 표현식으로 정의된 함수 -> (호이스팅) 선언, 할당 분리
// => 참조하려는 함수 addEventListener() 메서드보다 반드시 위에 작성
const clickEvent = () => {
alert("button Click");
}
btnEl.addEventListener("click", clickEvent);
</script>
7. 이벤트 객체와 this
이벤트 객체 사용하기/ 이벤트 취소하기/ this 키워드 사용하기
이벤트 객체
- 이벤트 타입에 따라 발생하는 이벤트의 각종 정보가 들어 있는 객체 집합
- 개발자가 직접 생성 X, 이벤트 발생 -> 실행되는 함수의 매개변수로 같이 전달
이벤트 객체 사용하기
- 클릭 이벤트의 PointerEvent 객체의 주요 속성
- clientX: 마우스가 클릭된 Y좌표(수평 스크롤 포함 X)
- clientY: 마우스가 클릭된 Y좌표(수평 스크롤 포함 X)
- pageX: 마우스가 클릭된 x좌표(수평 스크롤 포함 O)
- pageY: 마우스가 클릭된 Y좌표(수평 스크롤 포함 O)
- screenX: 모니터의 왼쪽 위 모서리를 기준으로 마우스가 클릭된 x좌표
- screenY: 모니터의 왼쪽 위 모서리를 기준으로 마우스가 클릭된 x좌표
- KeyboardEvent 객체의 주요 속성
- keyCode: 키보드에서 눌린 키의 유니코드 값 반환
- ctrlKey: Ctrl 키 눌렸으면 true, 아니면 false
- altKey: alt 키 눌렸으면 true, 아니면 false
- shiftKey: shift 키 눌렸으면 true, 아니면 false
이벤트 취소하기
HTML 태그 중 일부: 기본으로 이벤트 적용
=> preventDefault() 메서드: 태그에 기본으로 연결된 이벤트 취소
// a 태그에 연결된 클릭 이벤트 취소
<a href="https://www.naver.com">네이버 이동</a>
<a href="https://www.daum.net">다음 이동</a>
<script>
const aEls = document.querySelectorAll("a");
for(let i = 0; i < aEls.length; i++){
aEls[i].addEventListener("click", function(e){
// 기본 이벤트 취소
e.preventDefault();
});
}
</script>
this 키워드
- 이벤트가 발생한 요소 노드 바로 가리킴
- 이벤트 발생 시점에 대상 노드 조작할 수 있음
- 화살표 함수 -> this 범위 달라져 this가 이벤트 발생 노드 가리키지 X
- this가 window 객체 가리킴
- => 이벤트 객체의 target 속성 사용
// 기존 코드에서 p 태그 클릭 -> 텍스트 색상: red/ 이미 red -> black
<script>
const pEls = document.querySelectorAll("p");
pEls.forEach((el) => {
el.addEventListener("click", function(){
if(this.style.color === 'red'){
this.style.color = 'black';
}else{
this.style.color = 'red';
}
});
})
// 화살표 함수
// (X)
/* pEls.forEach((el) => {
el.addEventListener("click", () => {
console.log(this);
});
}) */
// (O)
pEls.forEach((el) => {
el.addEventListener("click", (e) => {
console.log(e.target);
});
})
</script>
출처