[JavaScript] DOM이란 무엇일까?

김유진·2022년 9월 29일
0

Javascript

목록 보기
11/22

html/css만 이용하면 될 것 같은데, javascript를 왜 사용할까요?

그것은 바로 조건에 맞는 변화를 주거나, 사용자의 동작이 있을 때 이를 동적으로 처리하기 위함이에요. 웹 문서에는 우리가 이런 것을 신경 써야 할 것이 너무너무 많아요. 텍스트와 이미지가 각각 몇개인지도 알아야 하고, 이것이 어디서 와서 제어를 하는 것인지도 신경 써야 해요.

우리는 이런 모든 정보 요소를 자바스크립트로 프로그래밍을 해야 해요. 이때 우리는 문서 객체 모델(DOM)에 대해서 알고 있어야 해요.

DOM이란?

자바스크립트를 이용하여 웹 문서에 접근하고, 제어할 수 있도록 객체를 사용하여 웹 문서를 체계적으로 정리하는 방법

HTML 언어로 작성한 웹 문서의 DOM을 HTML DOM이라고 하고, XML 문서에는 XML DOM이라고 합니다. 저희는 html을 배웠으니까 html dom을 기준으로 생각해보도록 해요~~

DOM은 웹 문서를 하나의 객체로 정의해요. 그리고 웹 문서를 이루는 텍스트나 이미지, 표 등의 모든 요소도 각각 객체로 정의합니다! 웹 문서 하나 전체는 document 객체이고, 삽입한 이미지는 image 객체예요. 이처럼 DOM은 웹 문서와 그 안에 모든 요소를 객체로 인식하고 처리합니다.

우리 이전에 브라우저 객체에 대한 실습을 하면서 window를 이용하여 팝업 창을 띄우는 프로퍼티, 메서드를 이용해본적이 있을 거예요! 웹 문서에 대한 객체도 이런 다양한 프로퍼티와 메서드가 존재해요. 객체 모델 구조를 나타내는 DOM 트리를 알아보도록 합시다!

DOM트리

자바스크립트로 DOM을 조작하려면, 실제 웹 문서가 DOM으로 어떻게 표현되는지 알아야 해요. DOM은 웹 문서의 요소를 부모 요소와 자식 요소로 구분합니다! 각 요소에서 사용한 내용, 속성도 모두 자식으로 인식해요. 다음 코드를 제가 그림으로 나타내볼게요.

<!DOCTYPE html>
<html lang = "ko">
<head>
    <meta charset = " UTF - 8 ">
    <title>DOM Tree에 대하여</title>
</head>
<body>
    <h1>안녕</h1>
    <img src = "images/mutsa.jpg" alt = "공부합시다">
</body>
</html>


부모 자식 관계를 나타낸 모습이에요.

더 나아가서 DOM의 관점에서 부모 자식 관계를 생각해볼게요.
DOM은 문서 안의 요소뿐 아니라 각 요소에서 사용한 내용과 속성도 자식으로 나타내요.

이렇게 부모와 자식 구조로 표시하면 나무 형태가 되니까 DOM 트리라고 합니다. 루트 노드를 시작으로 웹 문서에서 사용한 요소는 계층 구조를 이루어요!

DOM 트리의 구분 원칙을 정리해봅시다!

  1. 모든 HTML 태그는 요소(element) 노드입니다.
  2. HTML태그에서 사용하는 텍스트 내용은 자식 노드인 텍스트(text) 노드입니다.
  3. HTML태그에 있는 속성은 자식 노드인 속성(attribute) 노드입니다.
  4. 주석은 주석(comment) 노드입니다.


이렇게 웹 문서를 해석할 DOM 구조를 만드는 것이 중요해요. DOM 트리를 머릿속으로 그릴 수 있어야, 자바스크립트를 이용하여 객체에 접근하여 원하는 부분을 수정할 수 있어요!

DOM에 접근하기

CSS에서는 class, id 태그 등의 스타일을 각각 구별하여 정의하여야 해요. 이런 것을 우리가 '선택자' 라고 하였죠. 이 선택자를 이용하여서 DOM에 접근하는 방법을 알아봅시다!

id 선택자로 접근하는 getElementById()메서드

HTML태그의 id속성은 HTML 요소가 문서 안에서 중복되지 않도록 사용하는 CSS 선택자예요. 이 메서드를 이용하게 되면 특정한 id가 포함된 DOM 요소에 접근할 수 있어요.

요소명.getElementById("id명")

예를 들어, id값이 heading인 요소에 접근하려면 다음과 같이 사용해요.

document.getElementById("heading")
class값으로 접근하는 getElementsByClassName()메서드

이 메서드는 class 선택자 이름이 들어 있는 DOM 요소에 접근해요!

요소명.getElementsByClassName("class명")

class 선택자는 웹 문서 안에 여러 요소에 사용 가능하므로, 이 친구가 반환하는 요소가 2개 이상일 수도 있어요!

그래서 Elements에 's'가 붙은 이유!!

document.getElementsByClassName("bright")

해당 메서드를 사용하게 되면 클래스 이름이 같은 DOM 요소들이 HTMLCollection객체로 저장됩니다! 이 친구는 배열과 비슷해서, 배열과 사용할 수 있으나, 배열은 아니예요~~

태그 이름으로 접근하는 getElementsByTagName()메서드

class나 id를 사용하지 않은 DOM 요소에 접근하려면 태그를 이용해야죠!

요소명.getElementsByTagName("태그명")

웹 문서 안에서 같은 태그를 사용하는 요소가 2개 이상 있을 수 있으므로, 이 친구도 HTMLCollection 형태로 저장됩니다!

document.getElementsByTagName("p")

다양한 방법으로 접근하는 querySelector(), querySelectorAll()메서드

위에서 살펴본 것의 반환값은 HTMLCollection 객체예요. 여기에는 HTML 요소만 저장됩니다.

그런데 DOM 트리의 텍스트, 속성 노드까지 자유롭게 제어하려면 해당 메서드를 사용해요. id 선택자처럼 반환값이 하나라면 querySelector()를 사용하고, 여러 값이 한꺼번에 반환된다면 querySelectorAll()을 사용합니다!

노드.querySelector(선택자)
노드.querySelectorAll(선택자 또는 태그)

id를 선택할 때는 '#'를 붙이고, class를 선택할 때는 '.'을 부착합니다! 태그는 기호 없이 태그명만 쓰면 되어요~

만약 querySelector로 class를 선택하였다면, 그 중에 첫번째 것만 반환합니다.

querySelector("#heading")
querySelectorAll(".bright")

이 친구들의 반환값은 노드이거나, 노드 리스트예요! 노드 리스트는 노드를 한꺼번에 여러 개 저장한 것과 동일하다고 생각하시면 됩니다!

웹 요소의 내용을 수정하는 innerText, innerHTML 프로퍼티

자바스크립트는 웹 요소의 내용도 수정할 수 있어요. 가장 쉬운 방법은 이 프로퍼티를 이용하는 것입니다. 이름만 봐도 알 수 있듯이, innerText 프로퍼티는 텍스트 내용을 표시하고, innerHTML은 HTML태그까지 반영하여 표시해요.

요소명.innerText = 내용
요소명.innerHTML = 내용

다음은 Date 객체를 사용하여 현재 날짜와 시간을 나타내는 예제예요. 날짜와 시간을 그대로 innerText 프로퍼티로 표시할 때와 innerHTML 프로퍼티로 <em> 태그와 같이 표시할 때 어떤 차이가 있는지 확인해보세요!

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>innerText, innerHTML 프로퍼티</title>
</head>
<body>
	<button onclick="inntext()">innerText로 표시하기</button>
	<button onclick="innhtml()">innerHTML로 표시하기</button>
	<h1>현재 시각: </h1>
	<div id="current"></div>
	
	<script>
		var now = new Date();

		function inntext(){
			document.getElementById("current").innerText = now;
		}
		function innhtml() {
			document.getElementById("current").innerHTML = "<em>" + now + "</em>";
		}
	</script>
</body>
</html>

속성을 가져오는 getAttribute(), setAttribute()메서드!

웹 요소에 문서를 삽입할 때에는 태그 속성을 함께 사용하면, DOM 트리에 속성 노드가 추가되면서 속성에 접근하려면 getAttribute()메서드를 사용하고, 접근한 속성의 값을 바꾸려면 setAttribute()메서드를 사용합니다.

getAttribute("속성명")

속성을 가져오려면 다음과 같이 getAtrribute() 메서드에서 속성명을 지정합니다.
setAttribute()메서드를 사용하면 원하는 속성값으로 지정할 수 있습니다. 속성값이 이미 있다면 새로운 속성값으로 수정하고, 아직 해당 속성이 없다면 속성과 속성값을 새로 추가합니다.

setAttribute("속성명", "값")

다음은 id="cup"인 인 이미지의 src 속성값을 가져오는 예제입니다! 큰 이미지를 클릭하면, 그 이미지의 경로 속성을 가져와 알람 창에 표시합니다!


<div id="prod-pic">
			<img src="images/coffee-pink.jpg" alt="에디오피아 게뎁" id="cup" width="200" height="200" onclick="displaySrc()">
				<div id="small-pic"> 
					<img src="images/coffee-pink.jpg" class="small">
					<img src="images/coffee-blue.jpg" class="small">
					<img src="images/coffee-gray.jpg" class="small">
				</div>
		</div>			
...
<script>
		function displaySrc() {
			var cup = document.querySelector("#cup");
			alert("이미지 소스 : " + cup.getAttribute("src"));
		}	
</script>

이런식으로 이미지의 주소를 나타냅니다!
자, 이제 하단의 작은 이미지를 클릭하였을 때, 큰 이미지로 바뀌게 하는 코드를 작성해볼까요.

이때에는 setAttribute()메서드를 이용합니다!


function changePic() {
      var newPic = this.src;
      cup.setAttribute("src", newPic);
    }

this.src를 통하여 현재 newPic에 대한 정보를 받아오고, 해당 주소로 이미지를 바꾼 것을 알 수 있습니다.

DOM에서 이벤트 처리해보기

이벤트 처리기 함수가 간단하다면, DOM 요소에 직접 연결할 수 있습니다!

예를 들어, 다음 예제는 img 요소를 가져와 변수에 저장한 후에, onclick을 사용하여 변수에 이벤트 처리기(함수)를 직접 연결합니다. 이미지를 클릭하면 알람 창이 나타나지만, 이미지 외의 다른 곳을 클릭하면 실행되지 않습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>DOM event 객체</title>
  <style>
    #container {
      width:300px;
      margin:10px auto;
    }
  </style>
</head>
<body>
  <div id="container">
    <img src="images/cup-1.png" id="cup">		
  </div>

	<script>
		var cup = document.querySelector("#cup");  // id = cup인 요소를 가져옴
    cup.onclick = function(){
      alert("이미지를 클릭했습니다");
    }
	</script>
</body>
</html>

이벤트가 발생하였을 때, 실행할 함수를 따로 정의해 두었다면 함수 이름을 이용하여 연결할 수 있습니다. 이 경우에는 함수 이름 다음에 괄호를 추가하지 않아요!
다음 예제는 이미지를 cup 변수로 저장한 후에, click 이벤트가 발생하였을 때 changePic() 함수를 실행합니다.

<script>
		var cup = document.querySelector("#cup");  // id = cup인 요소를 가져옴
    cup.onclick = changePic;  // cup을 클릭하면 changePic 함수 실행

    function changePic() {
      cup.src = "images/cup-2.png";
		}
</script>

querySelector를 통하여 cup 요소를 가져옵니다. 그 이후에 cup을 클릭하게 되면 그 속성인 src 속성을 다른 이미지로 교체합니다.

DOM에는 이벤트 정보를 저장하는 event 객체가 존재합니다. 이 객체에는 웹 문서에서 이벤트가 발생한 요소가 무엇인지, 어떤 이벤트가 발생하였는지 등의 정보가 들어 있습니다.
다음은 이미지에서 발생한 이벤트의 유형과 위치를 알람 창으로 보여주는 예제입니다. 여기에서 img 요소를 클릭하면, 그 위치를 확인하기 위하여 event 객체를 함수의 인수로 사용합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>DOM event 객체</title>
	<style>
    #container {
      width:300px;
      margin:10px auto;
    }
  </style>
</head>
<body>
	<div id="container">
    <img src="images/cup-1.png" id="cup">		
  </div>	

	<script>
		var cup = document.querySelector("#cup");  // id = cup인 요소를 가져옴
		cup.onclick = function(event) {
			alert("이벤트 유형: " + event.type + ", 이벤트 발생 위치 : " + event.pageX + "," + event.pageY);	
		}
	</script>
</body>
</html>

다음은 event 객체의 주요 프로퍼티와 메서드를 정리한 것입니다.

event 객체에서는 이벤트 정보만 들어 있습니다. 만약 이벤트가 발생한 대상에 접근하려면 이벤트 처리기에서 예약어 this를 이용해야 합니다. 다음 예제처럼 클릭한 이미지의 파일 경로를 알고 싶다면 this.src 와 같이 입력해야 합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>DOM event 객체</title>
  <style>
    #container {
      width:300px;
      margin:10px auto;
    }
  </style>
</head>
<body>
	<div id="container">
		<img src="images/cup-1.png" id="cup">	
	</div>
  
	<script>
		var cup = document.getElementById("cup");
		cup.onclick = function(event) {
			alert("클릭한 이미지 파일 : " + this.src);
		}
	</script>
</body>
</html>

이제 addEventListener() 메서드를 이용해봅시다.

지금까지 사용한 이벤트 처리기는 한 요소에 하나의 이벤트 처리기만 연결할 수 있었어요.

하지만 다음과 같이 addEventListener()메서드와 event 객체를 사용하면 한 요소에 여러 이벤트 처리기를 연결하여 실행할 수 있습니다. addEventListener()메서드는 끝에 세미콜론(;)을 꼭 붙여야 해요!

요소.addEventListener(이벤트, 함수, 캡처 여부);

이벤트는 이벤트 유형을 지정하고, click과 keypress처럼 on을 붙이지 않고 사용합니다. 함수는 이벤트가 발생하면 실행할 명령어나 함수를 지정합니다. 여기에서 함수를 정의할 때는 event 객체를 인수로 받습니다. 캡처 여부는 이벤트를 캡처하는지 여부를 지정하며, 기본값은 false이고, true와 false 중에서 선택 가능합니다. true이면 캡쳐링, false이면 버블링한다는 의미입니다. 이벤트 캡쳐링은 DOM의 부모 노드에서 자식 노드로 전달되는 것이고, 이벤트 버블링은 DOM의 자식 노드에서 부모 노드로 전달되는 것입니다.

다음은 이미지 위로 마우스 포인터를 올려두면, 다른 이미지로 바뀌었다가 내려놓으면 다시 원래 이미지로 돌아오는 예제입니다. addEventListener()메서드를 사용하여, changePic() 함수와 originPic() 함수를 이벤트 처리기로 사용합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>DOM event 객체</title>
  <style>
    #container {
      width:300px;
      margin:10px auto;
    }
  </style>
</head>
<body>
	<div id="container">
		<img src="images/easys-1.jpg" id="cover">	
  </div>
  
	<script>
		var cover = document.getElementById("cover");
		cover.addEventListener("mouseover",changePic, false); //마우스를 올려두면 changePic 실행
        cover.addEventListener("mouseout",originPic, false); //마우스를 내려두면 originPic 실행
    
    function changePic() {
      cover.src = "images/easys-2.jpg";
    }
    function originPic() {
      cover.src = "images/easys-1.jpg";
    }
	</script>
</body>
</html>

이 예제에서는 chagnePic과 originPic을 따로 선언하고 사용하였습니다. 그러나 단순히 이벤트를 처리하는 함수라면 다음 메서드 안에서 한번에 처리해도 무관합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>DOM event 객체</title>
  <style>
    #container {
      width:300px;
      margin:10px auto;
    }
  </style>
</head>
<body>
	<div id="container">
		<img src="images/easys-1.jpg" id="cover">	
  </div>
  
	<script>
		var cover = document.getElementById("cover");
		cover.addEventListener("mouseover",function() { //아예 한 줄 메서드로 지정! 
        cover.src = "images/easys-2.jpg";
    });

      cover.addEventListener("mouseout", function() { //아예 한 줄 메서드로 지정!
      cover.src = "images/easys-1.jpg";
    });  
	</script>
</body>
</html>

특정 이벤트에서 어떤 명령을 실행하는지 한눈에 파악할 수 있어서 더욱 편리합니다. ^^

자, 이제 CSS 속성에 접근하여봅시다.

자바스크립트를 이용하여 스타일 속성값을 가져와, 그 값을 원하는 대로 수정할 수 있어요. 자바스크립트에서는 각 요소의 스타일을 자유롭게 수정할 수 있으므로, 웹 문서에서 다양한 효과를 만들 수 있어요.

CSS 속성에 접근하려면 해당 스타일이 적용된 HTML 요소 다음에 예약어 style을 쓰고 속성을 작성합니다.

document.요소명.style.속성명

예를 들어 id가 desc인 요소의 글자를 파란색으로 변경하고 싶다면 다음과 같이 작성해볼까요!

document.getElementById("desc").style.color = "blue"

이렇게 color처럼 한 단어인 속성명은 그대로 사용하면 되지만, background-color 처럼 중간에 하이픈이 존재하는 속성은 두 단어를 붙여서 사용해요. ex) backgroundColor!! 이때 주의해야 할 것은 두 번째 글자를 대문자로 표현해야 해요.

다음은 사각형 위에 마우스 포인터를 올려놓으면 초록색 원으로 바뀌고, 내려놓으면 원래 도형으로 되돌아가는 예제입니다. 자바스크립트에서 이미지의 background-color, border-radius 속성을 다루는 방법을 잘 살펴보세요.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>DOM CSS</title>
	<style>
		#container {
			width:400px;
			margin:50px auto;
			text-align: center;
		}
		#rect {
			width:100px;
			height:100px;			
			border:1px solid #222;
			margin:30px auto;
			transition: 1s;
		}
	</style>
</head>
<body>
	<div id="container">
		<p>도형 위로 마우스 포인터를 올려놓으세요.</p>
		<div id="rect"></div>
	</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>
</html>

포인터를 올려두지 않았을 때


포인터를 올려놓았을 때.

짜잔! 직접 해보면 엄청 신기하답니다.

DOM에서 노드 추가, 삭제하기

다음은 노드 리스트에 대해서 알아볼게요.

DOM에서 새로운 노드를 만들어 추가하거나 삭제하려면 노드 리스트를 사용해야 해요.
노드 리스트는 무엇일까요? DOM에 접근할 때, querySelectorAll() 메서드를 사용하면, 노드를 한꺼번에 여러 개 가져올 수 있어요. 이 때의 노드 정보를 여러 개 저장한 것이 노드 리스트예요. 배열과 비슷하게 동작합니다!

노드 리스트가 무엇인지 알기 위하여 다음 과정을 하나씩 따라해볼까요 :)

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Web Programming</title>
	<link rel="stylesheet" href="css/nodelist.css">
</head>
<body>
	<h1>Web Programming</h1>
	<ul id="itemList">
		<li>HTML</li>
		<li>CSS</li>
		<li>Javascript</li>
	</ul>
</body>
</html>

해당 페이지를 열고 콘솔 창을 실행해보세요. 그리고 콘솔 창에 다음과 같이 입력해보길 바랍니다!

document.querySelectorAll("li")

완전한 배열은 아니지만 배열과 아주 비슷한 형태를 가지고 있지요! 노드 리스트는 배열과 비슷해서, 인덱스 번호로 특정 위치의 노드에 접근 가능합니다.

document.querySelectorAll("li")[1]

이렇게 하면 두번째 노드를 가져올 수 있어요.

이제 한번 새로운 DOM 노드를 추가해봅시다.
이 쯤에서 DOM 트리를 구성하는 기본 원칙이 기억이 안나신다구요?!! 다시 위로 가셔서 확인해보세요.
어떤 태그를 노드로 추가한다면, 단순히 태그에 해당하는 요소 노드 뿐만 아니라, 텍스트 노드와 속성 노드를 추가해야해요. 예를 들어 태그를 요소로 추가한다면 어떤 노드를 더 추가해야 할까요?

태그의 요소 노드와 속성 노드에 해당하는 src,alt의 노드도 추가될 테고.. 그 밖에 다른 속성도 사용한다면 더욱 많은 노드가 추가되겠지요.

이렇게 웹 문서의 DOM 트리에 새로운 노드를 추가하기 위해서는 그 문서에 새로운 소스 코드를 작성해야 해요.

새 노드를 추가할 때에는 웹 문서에 어떤 소스를 추가할지 먼저 생각하고, 그에 따라 요소 노드나 텍스트, 속성 노드 등을 만들어야 해요.

텍스트 노드를 사용하는 새로운 요소 추가하기

[더 보기] 링크를 클릭하면 그 아래에 간단한 텍스트가 표시되는 스크립트 소스를 작성해볼까요?

문서에는 단순히

태그 하나가 추가되어 보이지만, DOM에서는 여러 단계가 필요해요.

1. 요소 노드 만들기 - createElement() 메서드
DOM에 새로운 요소를 추가할 때 가장 먼저 할 일은 요소 노드를 만드는 것입니다. 새로운 p 요소를 추가해볼까요?

p만 뙇! 하고 추가된 모습 (글씨 죄송해용^^ ..)

var newP  = documnet.createElement("p");

하지만 createElement()메서드는 새로운 노드를 만들 뿐이지, 아직 웹 문서에 새로운 노드를 추가한 것은 아닙니다. 이제

태그에 내용에 해당하는 텍스트 노드도 만들어야 합니다!

2. 텍스트 노드 만들기 - createTextNode() 메서드

새로운 요소 노드를 만들었다면, 그 내용을 담는 텍스트 노드를 자식 노드로 만들어 연결해야죠. 새롭게 만든 p 요소에 들어갈 내용이 있는 텍스트 노드는 txtNode 변수로 저장하여 만들어 봅시다.

var txtNode = document.createTextNode("DOM은 documnent object model의 줄임말입니다.");

p요소의 텍스트 노드 추가

3. 자, 둥둥 떠 다니는 요소들을 만들었으니까 이제 이것을 연결해봅시다!

자식 노드 연결 - apppendChild()메서드
지금까지 새로운 p노드 (newP)와 사용할 텍스트 노드(txtNode)를 만들었어요. 아직까지는 노드를 만든 상태이며 부모노드, 자식노드가 서로 연결되어 있지 않아요. 이 메서드는 텍스트 노드나 속성 노드를 만들고 이것을 요소 노드에 연결할 때 사용합니다. 이때 appendChild()메서드를 사용하여 연결하는 노드는 자식 노드 중에서 맨 끝에 추가됩니다.

다음은 텍스트 노드 txtNode를 요소 노드 newP의 자식 노드로 연결하고, newP 노드를 다시

의 자식 노드를 연결해볼까요.

newP.appendChild(txtNode);
document.getElementById("info").appendChild(newP);


부모노드와 자식노드 연결한 DOM트리

첫번째 줄을 통하여서 newP노드에 txtNode를 추가한 것이고, 두번째 줄을 통하여 div태그에 newP 노드를 추가한 것입니다. :)

전체 코드 소스를 완성하여 보겠습니다!

[더 보기] 링크를 클릭하면 이제 p 태그가 나타나도록 하는 것이였죠?

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>DOM</title>
  <style>
    #container{
      width:500px;
      margin:10px auto;
      padding:20px;
    }
    #info {
      margin-top:20px;
    }
  </style>
</head>
<body>
  <div id="container">    
    <h1>DOM을 공부합시다</h1>
    <a href="#" onclick="addP(); this.onclick='';">더 보기</a>    
    <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>
</body>
</html>

더 보기 부분에 버튼이 새롭게 생긴 것을 알 수 있지요? 해당 버튼을 누르면 함수가 실행되도록 하는 것입니다. 한번 실제로 해보세요!

속성값이 있는 새로운 요소 추가하기

html 태그에서는 여러 가지 속성을 사용하여, 웹 요소를 제어합니다. 따라서 새로운 요소를 만들면 그와 관련된 속성 노드도 만들어서 자식 노드로 연결해야 합니다. 자. 이제 '더 보기' 링크를 클릭하면 텍스트는 물론 이미지까지 나타나게 하는 스크립트 소스를 한번 작성해 봅시다!

1. 요소 노드 만들기 - createElement()메서드
텍스트 노드를 추가했던 방법과 마찬가지로, createElement()메서드를 사용하여 새로운 이미지 노드를 만듭니다.

var newImg = document.createElement("img");

2. 속성 노드 만들기 - createAttribute() 메서드

document.createAttribute(속성명)

다음은 이미지 파일의 경로를 지정할 src와 대체 텍스트를 지정할 alt를 위해 속성 노드를 추가하는 예제입니다.

var srcNode = document.createAttribute("src");
var altNode = document.createAttribute("alt");
srcNode.value = "images/dom.jpg"; //src 속성값 지정
altNode.value = "돔 트리 예제 이미지";

속성값은 value 프로퍼티를 이용하여 지정하였습니다!

3. 속성 노드 연결하기 - setAttributeNode() 메서드
속성 노드는 요소 노드의 자식으로 연결해야 합니다. 이 때 setAttributeNode()메서드를 연결합니다.
만약 추가하려는 속성이 요소 노드에 이미 들어있따면 기존 속성 노드를 새 속성 노드로 대체하니까 주의해주세요!
아까 우리가 만든 요소에 새 속성을 추가하는 코드를 작성해봅시다.

newImg.setAttributeNode(srcNode);

4. 자식 노드 연결하기 - appendChild() 메서드
속성 노드까지 연결했지만, 아직 img 노드는 만들어만 두었잖아요!? 웹 문서의 DOM에 추가해야 하기 때문에 appendChild() 메서드를 사용하여 필요한 위치에 자식 노드를 추가해 보도록 합시다!

document.getElementById("info").appendChild(newImg);

이제 전체 코드를 완성하여서 [더보기] 버튼을 눌렀을 때 텍스트와 이미지가 보이게끔 확인해봅시다!

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>DOM</title>
  <style>
    #container{
      width:500px;
      margin:10px auto;
      padding:20px;
    }
    #info {
      margin-top:20px;
    }
  </style>
</head>
<body>
  <div id="container">    
    <h1>DOM을 공부합시다</h1>
    <a href="#" onclick="addContents(); this.onclick='';">더 보기</a>    
    <div id="info"></div>
  </div>
  <script>
    function addContents() {
      var newP = document.createElement("p");
      var txtNode = document.createTextNode("DOM은 Document Object Model의 줄임말입니다.");
      newP.appendChild(txtNode);
      
      var newImg = document.createElement("img");
      var srcNode = document.createAttribute("src");
      var altNode = document.createAttribute("alt");
      srcNode.value = "images/dom.jpg";
      altNode.value = "돔 트리 예제 이미지";
      newImg.setAttributeNode(srcNode);
      newImg.setAttributeNode(altNode);

      document.getElementById("info").appendChild(newP);
      document.getElementById("info").appendChild(newImg);
    }
  </script>
</body>
</html>

지난 실습들에서는 화면에 텍스트 필드에 입력한 내용을 화면에 표시하려면, document.write()문만을 사용하였어요. 이제 우리는 DOM을 공부하였으니, 텍스트 필드에 입력한 내용을 새로운 노드로 만들어서 화면에 표시해 봅시다 :)

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Web Programming</title>
	<link rel="stylesheet" href="css/nodelist.css">
</head>
<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>
</html>

해당 코드를 실행하면 다음과 같은 화면이 뜰 거예요.

텍스트 필드에 값을 여러 번 입력하게 되면 화면에 입력값이 여러 개 나타나도록 수정해봅시다!
먼저 요소의 id값을 확인해보세요. 텍스트 필드 요소의 id값은 subject입니다. 이제 텍스트 필드에서 입력받은 id값을 itemList에 표시해봐요!

우리가 새로 만들어야 하는 요소는 <ul>태그 사이에 <li>요소 노드를 만들어야 해요.

아래에 집중!

<ul id="itemList"></ul> 

텍스트 필드에 입력한 값을 가져와, 새로운 텍스트 노드를 만들고 li 요소 노드에다가 자식 노드로 추가해요.

다음 스크립트 소스를 추가해볼까요?

 <script>
    function newRegister(){ 
      var newItem = document.createElement("li"); //새로운 li 요소 노드 추가
      var subject = document.querySelector("#subject"); //폼의 텍스트 필드를 가져옴
      var newText = document.createTextNode(subject.value); //텍스트 필드의 값을 노드로 추가합니다.
      newItem.appendChild(newText); //텍스트 노드를 자식 노드로 연결합니다.

      var itemList = document.querySelector("#itemList"); //부모 노드를 가져옵니다.
      itemList.appendChild(newItem); //새로만든 newItem이라는 노드를 부모 노드에 추가합니다.

      subject.value=""; //다음 입력을 위하여, 텍스트 필드 값을 비웁니다.
    }
  </script>

요소를 만드는 함수를 작성했으므로, 버튼을 클릭하면 실행하도록 만들어야 합니다. 기존의 <button> 태그를 다음과 같이 수정해보세요.
이때, return false를 추가하는 이유는 버튼의 기본 기능인 submit 역할을 취소하기 위해서입니다.
해당 기능을 취소시켜놓지 않으면, 함수를 실행하지 않고 기본 기능을 먼저 실행하기 때문입니다. 기본 기능을 끄고 실행하라고 알려주기 위해 작성합니다.


 <button onclick="newRegister(); return false;"">추가</button>

잠깐! 마지막에 작성한 글을 맨 위로 나타내고 싶은데 어떻게 하나요?

appendChild() 메서드를 사용하면 아까 말씀드린 것처럼, 새로운 노드를 부모 노드의 맨 끝에 추가해요. 그래서 가장 마지막에 입력한 값을 목록 맨 아래에 표시가 되어요. 순서를 바꾸어 표시하고 싶다면 부모 노드와 자식 노드의 관계를 파악한 후에, 마지막 자식 노드를 맨 앞에 추가하면 돼요.

itemList의 자식 노드 중에서 맨 앞의 자식 노드는 itemList.childNodes[0]으로 접근 가능해요. 이 노드의 앞에 새로운 노드를 추가하도록 수정하면 돼요.

itemList.appendChild(newItem);

해당 코드를 아래와 같이 바꾸어볼까요.

itemList.insertBefore(newItem, itemList.childNodes[0]);

노드 삭제하기

지금까지 새로운 노드를 추가하는 방법으로, createElement()와 appendChild() 메서드를 살펴보았어요. 이제 특정 노드를 삭제하려면 어떻게 해야 할까요?

노드를 삭제할 때, 기억해 둘 것은 부모 노드에서 자식 노드를 삭제해야 해요. 즉 삭제하고 싶은 것이 있으면 무조건!!!! 부모 노드를 찾아보시길 바라요. 그래서 노드를 삭제하는 메서드 외에, 부모 노드를 찾는 프로퍼티가 필요해요.

parentNode 프로퍼티

DOM 트리의 노드는 바로 삭제할 수 없으므로, 먼저 부모 노드에 접근해야 해요. 그러려면 삭제할 노드의 부모 노드를 찾아가는 방법을 알아야 해요. parentNode 프로퍼티는 현재 노드의 부모 노드에 접근하여 부모 노드의 요소 노드를 반환해요.

노드.parentNode

이 프로퍼티 반환값을 통하여 부모를 찾을 수 있는 것이지요!
업로드중..

여기서 li의 두번째 요소인 CSS의 부모 노드를 찾으니까 li 요소의 부모 노드인 ul 노드가 보이네요.

이렇게 parentNode 프로퍼티를 사용하면 현재 노드의 부모 노드를 찾을 수 있습니다.

자, 이제 본격적으로 지워봅시다! removeChild()메서드를 사용해볼게요.

부모노드.removeChild(자식노드)

이렇게 해서 지우면 됩니다. li 노드를 삭제하려면 어떻게 해야 할까요?!

li.parentNode.removeChild(li)

자. 앞에 우리가 텍스트 필드에 입력한 내용을 화면에 표시하는 연습을 하였어요. 이제 화면에 표시한 내용을 클릭하여 삭제하는 방법에 대해서 알아보도록 할게요.

입력한 텍스트를 가져온 후에, 거기에서 click 이벤트가 발생하였을 시에 그 항목에 대한 부모 노드를 찾아서 li 요소를 삭제하면 돼요. 기존에 작성한 newResigter 함수에 다음과 같이 코드를 추가해보세욧~


function newRegister(){ 
   ...
      var items = document.querySelectorAll("li"); //모든 항목을 가져옵니다.
      for (i = 0; i < items.length ; i++){
        items[i].addEventListener("click",function(){ //해당 항목을 클릭하였을 때 발생하는 이벤트
          if(this.parentNode) //만약 부모 노드가 있다면
            this.parentNode.removeChild(this); //부모 노드에서 삭제해주세요.
        }); 
      }
    }
  </script>

삭제되는것이 확인될 거예여~

0개의 댓글