17-1 문서 객체 모델 (DOM)
1. 문서 객체 모델 알아보기
2. DOM 요소에 접근하고 속성 가져오기
문서 계층 구조
자바스크립트에서는 프로그래밍 할수있는 모든 대상을 객체화함
웹 문서의 요소들을 프로그래밍하기 위해서는 각각의 요소들을 객체화시켜야하고, 이를 문서 객체 모델이라 함
문서 객체 모델(DOM)
: 자바스크립트를 이용하여 웹 문서에 접근하고 제어할 수 있도록 객체를 사용해 웹 문서를 체계적으로 정리하는 방법
예) 웹 문서 전체는 document 객체, 삽입한 이미지는 image 객체로 관리함
웹 문서의 요소(태그)들은 다음과 같이 요소의 계층 관계로 나타낼 수 있다
이 요소(태그)들만으로는 웹문서를 다 이해할 수 없음
-> 각 태그의 속성, 태그가 감싸고 있는 텍스트의 내용까지 포함해서 구성하는 것이 DOM 트리임
DOM 트리
웹 문서에 있는 요소들 간의 부모, 자식 관계를 계층 구조로 표시한 것
나무 형태가 되기 때문에 DOM 트리라고 함
노드(node) : DOM 트리에서 가지가 갈라져 나간 항목
루트 노드(root node) : DOM 트리의 시작 부분(html)
DOM을 구성하는 원칙
모든 html 태그는 요소 노드(element node) - html, head, body, meta, title, h1, img
웹 문서의 텍스트 내용은 요소 노드의 자식 노드인 텍스트 노드(text node) - Do it!
태그의 속성은 요소 노드의 자식 노드인 속성 노드(attribute node) - charset="...", src="...", alt="..."
주석은 주석 노드(comment node)
웹 문서의 내용은 다음과 같이 DOM 트리로 구성할 수 있음
meta의 속성인 charset="..."은 요소 노드인 meta의 자식 노드인 속성 노드
h1이라는 요소 노드에 텍스트 노드인 Do it! 이 자식 노드로 연결됨
DOM 요소에 접근하기
웹 문서에서 원하는 요소를 찾아가는 것을 '접근한다(access)' 고 함
접근->요소를 가져와서->변수로 저장->변수에 여러 메서드, 프로퍼티를 사용해 원하는 프로그래밍을 하게 됨
웹 요소에 접근할 때는 두 가지 형태의 메서드를 사용하게 됨
1)
getElementById() 메서드
[기본형] 요소명.getElementById("id명")
getElementsByClassName() 메서드
[기본형] 요소명.getElementsByClassName("class명")
getElementsByTagName() 메서드
[기본형] 요소명.getElementsByTagName("태그명")
: 자바스크립트 초기부터 사용하던 메서드들임
이 메서드들은 웹 요소에 접근하려 할때 접근할 수단(id값, 클래스명, 태그명)에 따라 선택하고, 수단에 따라 각각의 메서드를 따로 사용해주어야 함
class선택자는 여러번 사용 가능하므로 element's'
마찬가지로 같은 태그가 여러번 반복 사용될 수 있으므로 element's'
둘은 반환값이 2개 이상일 수 있고, 이 값들은 HTMLCollection 객체에 저장됨, 인덱스를 통해 각 값들에 접근할 수 있음
2)
querySelector() 메서드, querySelectorAll() 메서드
[기본형]
노드.querySelector(선택자)
노드.querySelectorAll(선택자 또는 태그)
: 이 두 메서드들은 1)의 메서드들과 달리 웹 요소에 대한 접근 수단에 관계없이 사용할 수 있음
id명으로 접근하고 싶다면 해시 기호 # 를, 클래스명으로 접근하고 싶다면 앞에 마침표 . 를, 태그로 접근하고 싶다면 기호 없이 태그명을 써주면 됨
querySelector()는 한 개의 값만 반환함
querySelectorAll()은 반환값이 여러개일 때 모두 반환->노드 리스트(배열과 비슷, 인덱스로 저장 및 접근)로 저장됨
클래스나 태그는 반환하는 값이 여러개 일 수 있음. 이때 querySelector()를 사용하면 반환값이 하나뿐이므로 여러 요소 중 첫번째 요소만 가져오게 됨. 따라서 모든 요소에 접근하고 싶다면 querySelectorAll()을 사용하면 됨
DOM 요소에 접근하고 속성 가져오기
getAttribute() 메서드 : 속성 노드의 값을 가져옴
[기본형] getAttribute("속성명")
setAttribute() 메서드 : 속성 노드의 값을 바꿈
[기본형] setAttribute("속성명", "바꿔넣을 값")
특히 image 같은 경우는 속성을 많이 사용하게 됨
<img sre="images/coffe-pink.jpg" alt="에디오피아 게뎁" id="cup" width="200" height="200" onclick="displaySrc()">
->
이미지 파일의 경로를 알고 싶을때 :
var cup = document.querySelector("#cup"); // id = "cup" 인 요소에 접근
cup.getAttribute("src"); // cup의 src 속성 값을 가져옴
setAttribute()를 통해 이미지 파일의 경로를 바꿔주어 다른 이미지로 변경할 수도 있음
17-2 문서 객체 모델 (DOM)
3. DOM에서 이벤트 처리하기
이벤트 처리하기- 방법 1
이미지 클릭하면 알림 창이 뜨도록 처리해보자
보통 태그의 id값과 자바스크립트에서 변수 이름을 같이 해주는 경우가 많음
(함수 미리 정의x, 정의하며 즉시 실행)
변수.on이벤트 = function() { 실행할 명령; }
<body>
<div id="container">
<img src="images/cup-1.png" id="cup">
</div>
<script>
var cup = document.querySelector("#cup"); // 변수로 지정
cup.onclick = function() { // on이벤트 = 이벤트 처리 함수
alert("이미지를 클릭했습니다.");
}
</script>
</body>
이벤트 처리하기- 방법 2 : 미리 함수를 만들어놓고, 그 함수를 연결해서 사용
이미지를 클릭했을 때 다른 이미지로 변경하는 함수 작성
(함수를 미리 정의해놓았을 때)
변수.on이벤트 = 정의한함수이름;
<body>
<div id="container">
<img src="images/cup-1.png" id="cup">
</div>
<script>
var cup = document.querySelector("#cup"); //변수 지정, 이벤트에 정의한 함수 연결
cup.onclick = changePic; // changePic 뒤에 괄호 () 붙이지 않음 주의
function changePic() {
cup.src = "images/cup-2.png"; // 변수 cup의 src속성을 바꿔줌
}
</script>
</body>
예약어 this
이벤트가 발생한 대상에 접근하고 싶을 때 예약어 this를 사용함
<body>
<div id="container">
<img src="images/cup-1.png" id="cup">
</div>
<script>
var cup = document.querySelector("#cup");
cup.onclick = function() {
alert("현재 이미지 파일 경로는 " + this.src); // this는 click이벤트가 일어난 cup을 말함
}
</script>
</body>
여기서 말하는 this는 click이벤트가 발생한 대상인 cup(= id가 cup = img 태그)
이벤트 처리하기- 방법 3 : addEventListener() 메서드 사용하기
addEventListener() 메서드
[기본형] 요소.addEventListener(이벤트, 함수, 캡쳐여부);
이벤트 : 이벤트 유형을 지정함. 단, 이벤트 앞에 on을 붙이지 않고 사용함
함수 : 이벤트가 발생하면 실행할 명령이나 함수를 지정함. 여기서 함수를 정의할 때는 event객체를 인수로 받음
event 객체는 이 이벤트가 어떤 요소에서 발생했는지 또는 어떤 이벤트가 발생했는지, 이벤트가 발생한 위치가 어딘지 등의 정보를 가지고 있음
캡쳐여부 : 이벤트를 캡쳐하는지 여부를 지정함=부모요소와 자식 요소가 있을 때, 부모요소에서 발생한 이벤트가 자식요소에게 전달되는지 혹은 자식요소에서 발생한 이벤트가 부모요소에게 전달되는지를 의미함
기본값은 false(버블링, 자식->부모로 전달)이고 true와 false 중에서 선택할 수 있음.
true이면 캡쳐링, false이면 버블링한다는 의미임.
이벤트 캡쳐링은 DOM의 부모 노드에서 자식 노드로 전달되는 것이고, 이벤트 버블링은 DOM의 자식 노드에서 부모 노드로 전달되는 것임
예)
화면에 나타난 이미지(easys-1.jpg)에 마우스를 올리면 다른 이미지(easys-2.jpg)로 변경, 마우스를 밖으로 내리면 원래 이미지(easys-1.jpg)로 돌아오도록 하자
<body>
<div id="container">
<img src="images/easys-1.jpg" id="cover">
</div>
<script>
var cover = document.getElementById("cover");
cover.addEventListener(mouseover, changePic, false); // false는 생략가능
cover.addEventListener(mouseout, originPic, false);
function changePic() {
cover.src="images/easys-2.jpg";
}
function originPic() {
cover.src="images/easys-1.jpg";
}
</script>
</body>
이벤트 처리기로 사용할 함수를 미리 정의하지 않고 addEventListener() 안에서 바로 정의하여 사용할 수도 있음
cover.addEventListener(mouseout, function() { // 함수를 미리 정의하지 않고도 바로 사용가능
cover.src = "images/easys-1.jpg";
});
DOM에서 스타일 다루기
DOM에서 css 스타일에 접근하거나 스타일 값을 변경할 수도 있음
<head>
<style>
#rect { <!-- 사각형을 만듦 -->
width:100px;
height:100px;
border:1px solid #222;
margin:30px auto;
transition:1s;
}
</style>
</head>
<body>
<div id="rect"></div>
<script>
var myRect = document.querySelector("#rect");
myRect.addEventListener("mouseover", function() { // mouseover이벤트 처리
myRect.style.backgroundColor = "green"; // myRect요소의 배경색
myRect.style.borderRadius = "50%"; // myRect 요소의 테두리 둥글게 처리
});
myRect.addEventListener("mouseout", function() { // mouseout 이벤트 처리
myRect.style.backgroundColor = ""; // myRect 요소의 배경색 지우기
myRect.style.borderRadius = ""; // myRect 요소의 테두리 둥글게 처리 안함
});
</script>
</body>
변수.style.backgroundColor => 요소의 css style에서 background-color 속성을 바꿀 수 있음(하이픈 없애고 뒷단어 첫글자 대문자로)
마찬가지로, css의 border-radius 속성을 자바스크립트에서는 style.borderRadius 로 변경할 수 있음
여기서는 요소에 마우스를 올리면(이벤트) 테두리가 둥글어지며 배경색이 초록색이 되도록 지정,
마우스를 내리면 원래대로 돌아오도록 처리했는데
style에서 transition을 1초 지정했기 때문에 천천히 바뀌고 천천히 돌아오는 것을 볼 수 있음
17-3 문서 객체 모델 (DOM)
4. Dom에서 노드 추가, 삭제하기
쇼핑몰 등 사이트에서 크기 등 옵션을 선택하면 하단에 원래는 보이지 않던 항목이 나타나는 것을 볼 수 있음
이와같이 기존에 보이지 않던 내용이 나타나거나, 삭제하면 추가되었던 노드가 사라지게 할 수 있음
웹문서에서는 하나하나의 요소를 노드로 관리하므로 노드에 접근해서 삭제, 추가할 수 있음
텍스트 내용이 있는 노드 추가하기
예) '더보기' 링크를 클릭하면 텍스트 표시하기 => 텍스트 노드 추가
h1을 이용한 제목 텍스트('DOM을 공부합시다')와
a 태그를 이용한 '더보기' 라는 링크, id값이 'info'인 div 태그가 있는 문서.
더보기를 클릭하면 기존에는 없었던 텍스트 한줄이 화면에 나타남
<div id="container">
<h1>DOM을 공부합시다</h1>
<a href="#" onclick="addP(); this.onclick'';">더보기</a>
<!-- 위에서 this.onclick='' 이 없으면 링크를 클릭할 때마다 계속 addP() 함수가 실행됨-->
<div id="info"></div>
</div>
<script>
function addP() {
var newP = document.createElement("p");
var txtNode = document.createTextNode("DOM은 document object model의 줄임말입니다");
newP.appendChild(txtNode);
document.getElementById("info").appendChild(newP);
}
</script>
1. 요소 노드 만들기 - createElement() 메서드 : DOM트리 상에서 요소 노드가 일단 하나 만들어짐
[기본형] document.createElement(노드명)
우리는 텍스트를 표시할 것이기 때문에 p 요소노드를 만들것임.
=> var newP = document.createElement("p");
2. 텍스트 노드 만들기 - createTextNode() 메서드 : DOM트리 상에서 텍스트 노드도 따로 하나 만들어짐
[기본형] document.createTextNode(텍스트)
요소에서 텍스트 내용은 텍스트 노드에 따로 저장되므로 텍스트 노드를 메서드를 이용해 만들어줌
=> var txtNode = document.createTextNode("DOM은 document object node의 줄임말입니다.");
3. 자식 노드 연결하기 - appendChild() 메서드
[기본형] 부모노드.appendChild(자식노드)
텍스트 노드는 요소 노드의 자식노드임 => newP.appendChild(txtNode);
p 요소노드는 내가 p요소를 표시해주려고 하는 요소인 div(id값이 info)의 자식노드로 추가
=> document.getElementById("info").appendChild(newP);
=> a 태그인 '더보기' 링크 클릭시 addP() 함수 실행, addP()는 요소노드, 텍스트노드를 만들고 자식노드로 연결 후 p 요소 노드를 div의 자식노드로 연결하여 p태그의 텍스트가 화면에 표시되게 됨
속성과 속성 값이 있는 노드 추가하기
텍스트가 아니라 속성값이 있는 이미지 등을 삽입하는 경우를 생각해보자
이때는 속성 노드도 함께 만들어줘야 함
예) '더보기' 링크를 클릭하면 텍스트와 함께 이미지 표시하기
1. 요소 노드 만들기 - createElement() 메서드
이미지를 삽입하기 위해 img 요소 노드를 생성함
=> var newImg = document.createElement("img");
2. 속성 노드 만들기 - createAttribute() 메서드
[기본형] document.createAttribute(속성명)
img 태그는 여러 속성(파일 경로 및 대체텍스트)을 가지므로 속성노드도 만들어주어야 함
속성노드에 value 프로퍼티를 이용해 속성값을 지정해줌
=>
var srcNode = document.createAttribute("src");
var altNode = document.createAttribute("alt");
srcNode.value = "images/dom.jpg"; // src 속성값 지정
altNode.value = "돔 트리 예제 이미지"; // alt 속성값 지정
3. 속성 노드 연결하기 - setAttributeNode() 메서드
[기본형] 요소명.setAttributeNode(속성노드)
=>
img 요소노드에 src, alt 속성 노드 연결하기
newImg.setAttributeNode(srcNode);
newImg.setAttributeNode(altNode);
4. 자식 노드 연결하기 - appendChild() 메서드
img 노드도 연결해주어야 함
=>
document.getElementById("info").appendChild(newImg);
노드 삭제하기
노드를 삭제할 때는 자신을 스스로 삭제할 수는 없고, 부모노드에서 자식노드를 삭제해야함
-> 노드를 삭제하려면 부모노드부터 찾아야 함
parentNode 프로퍼티
: 현재 노드의 부모 노드에 접근하여 부모노드의 요소 노드를 반환함
[기본형] 노드.parentNode
removeChild() 메서드
: 자식 노드를 삭제함
[기본형] 부모노드.removeChild(자식노드)
예)
텍스트필드에 값을 입력하면 필드 아래쪽에 입력한 내용이 표시되도록 하자
값을 입력 > 엔터 > 하단에 입력한 값이 줄줄이 표시됨
텍스트노드 추가하는 방법을 이용함
<body>
<div id="container">
<h1>Web Programming</h1>
<p>공부할 주제를 기록해보세요</p>
<form action="">
<input type="text" id="subject" autofocus>
<button>추가</button>
</form>
<hr>
<ul id="itemList"></ul>
</div>
</body>
form 태그를 이용해서 input 텍스트필드 안에 내용을 입력할 수 있게 되어있음
텍스트필드의 id값은 subject임
표시할 내용은 ul 태그를 이용해서 목록형태로 표시할 것임
=>
우리가 만들 요소노드는 li가 됨(텍스트를 하나하나 입력할 때마다 li가 하나씩 추가되는 것임)
표시할 텍스트 내용은 텍스트필드에 입력된 값을 가져와서 텍스트노드로 사용할것임
<body>
<div id="container">
<h1>Web Programming</h1>
<p>공부할 주제를 기록해보세요</p>
<form action="">
<input type="text" id="subject" autofocus>
<button onclick="newRegister(); return false;">추가</button>
</form>
<hr>
<ul id="itemList"></ul>
</div>
<script>
function newRegister() { // '추가' 버튼을 누르면 실행될 함수
var newItem = document.createElement("li");
var subject = document.querySelector("#subject");
var newText = document.createTextNode(subject.value); //subject.value=텍스트필드 안의 값
newItem.appendChild(newText);
document.querySelector("#itemList").appendChild(newItem);
}
</script>
</body>
<button onclick="newRegister();"> 까지만 입력하게되면, 텍스트필드에 입력한 내용이 필드 하단에 잠깐 나타났다가 사라져버림. 왜냐하면 이 버튼의 역할이 계속 지속되고있기 때문=> 버튼의 역할을 취소시켜줘야 함(return false;)
button이나 input 타입의 submit 등은 실제 자기의 역할 말고 다른 기능을 하도록 하기 위해서는 return false를 사용해주어야 함
그러나 텍스트필드에 입력해준 값이 엔터를 치고 나서고 그대로 남아있는 문제가 있음
=> 함수 마지막에 subject.value = ""; 를 추가해줌
<body>
<div id="container">
<h1>Web Programming</h1>
<p>공부할 주제를 기록해보세요</p>
<form action="">
<input type="text" id="subject" autofocus>
<button onclick="newRegister(); return false;">추가</button>
</form>
<hr>
<ul id="itemList"></ul>
</div>
<script>
function newRegister() { // '추가' 버튼을 누르면 실행될 함수
var newItem = document.createElement("li");
var subject = document.querySelector("#subject");
var newText = document.createTextNode(subject.value); //subject.value=텍스트필드 안의 값
newItem.appendChild(newText);
document.querySelector("#itemList").appendChild(newItem);
subject.value = "";
}
</script>
</body>
이제 추가해준 값을 삭제해보자(항목 클릭->삭제되도록)
추가해준 요소의 부모요소를 찾아가서 삭제해야함
일단 삭제하기 위해서는 화면에 표시된 항목들을 클릭하는 요소(여기서는 li)가 있는지 살펴보자
텍스트필드에 입력하여 화면에 나타난 값들을 items에 넣음,
items의 i번째 항목에 click이벤트가 발생하면
-> 해당 항목(li)의 부모요소가 있는지 if문 통해 확인
-> 부모요소가 있다면,
해당요소.부모요소.removeChile(해당요소)
로 클릭한 해당 요소 삭제함
<body>
<div id="container">
<h1>Web Programming</h1>
<p>공부할 주제를 기록해보세요</p>
<form action="">
<input type="text" id="subject" autofocus>
<button onclick="newRegister(); return false;">추가</button>
</form>
<hr>
<ul id="itemList"></ul>
</div>
<script>
function newRegister() { // '추가' 버튼을 누르면 실행될 함수
var newItem = document.createElement("li");
var subject = document.querySelector("#subject");
var newText = document.createTextNode(subject.value); //subject.value=텍스트필드 안의 값
newItem.appendChild(newText);
document.querySelector("#itemList").appendChild(newItem);
subject.value = "";
var items = document.querySelectorAll("li"); // 추가해준 li 항목들을 다 찾음
for(let i = 0; i < items.length; i++) {
// 클릭하는 항목이 있을 때 함수(항목을 삭제함)를 실행하도록 할 것
items[i].addEventListener("click", function(){
if(this.parentNode) { //items[i]에 부모노드가 있을때만 실행
this.parentNode.removeChild(this);
}
});
}
}
</script>
</body>
* if문의 조건식에 있는 값을 boolean형으로 형변환할때, 대부분의 값들은 true도 변환됨
false로 변환되는 값 : false, null, NaN, undefined, 0, 빈문자열("")
'HTML/CSS/Javascript' 카테고리의 다른 글
HTML5, CSS3를 이용해서 간단하게 웹 페이지 만들어보기 (0) | 2024.01.20 |
---|---|
[Javascript/Jquery] Ajax 정리 (0) | 2023.10.27 |
[Do it! HTML+CSS+자바스크립트 웹 표준의 정석] 16 (0) | 2023.08.13 |
[Do it! HTML+CSS+자바스크립트 웹 표준의 정석] 15 (0) | 2023.08.13 |
[Do it! HTML+CSS+자바스크립트 웹 표준의 정석] 13~14 (0) | 2023.08.08 |