<!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 - Create & Add Node</title>
<link rel="stylesheet" href="css/nameList.css">
</head>
<body>
<div id="container">
<h1>참가 신청</h1>
<form action="">
<input type="text" id="userName" placeholder="이름" required>
<button onclick="newRegister();return false;">신청</button>
</form>
<hr>
<div id="nameList"></div> // 신청 명단이 표시될 영역
</div>
</body>
</html>
1. 버튼에 이벤트 함수 지정하기
이 프로그램에서는 텍스트 필드에 이름을 입력한 후 [신청] 버튼을 누르면 가로줄 아래에 신청자 명단이 표시됩니다. 먼저 <button> 태그에 click 이벤트가 발생했을 때 실행할 newRegister() 함수를 지정합니다. 이때 return false를 추가하는 것은 원래 버튼의 기능(입력 내용을 서버로 전송하는 기능)을 사용하지 않겠다는 뜻입니다.
2. 이벤트 함수 정의하기
이제부터 작성하는 소스는 register.js 문서에 추가할 자바스크립트 소스입니다. 먼저 [신청] 버튼을 눌렀을 때 실행하기로 지정한 newRegister() 함수의 내용을 작성해 보겠습니다.
register.html 문서에서는 신청자 명단을 표시할 때 <p>태그를 사용할 것입니다.다음 소스를 사용해 p 요소를 만들고 newP변수에 저장합니다. 머릿속으로는 DOM 트리에 어떤 노드가 어떻게 만들어지고 연결되는지를 계속 생각하고 있어야 합니다.
function newRegister() {
var newP = document.createElement("p"); // 새 p 요소 만들기
}
p 요소를 만들었으므로 <p>태그에 입력할 텍스트 노드를 만들어야 됩니다. <p>태그에서는 사용자가 입력한 이름(텍스트필드의 내용)을 표시할 것이므로 우선 텍스트 필드에 입력한 이름을 가져와 userName 변수에 저장합니다. 그리고 createTextNode() 함수로 텍스트 노드를 만들 때 userName 값을 사용합니다.
function newRegister() {
var newP = document.createElement("p"); // 새 p 요소 만들기
var userName = document.querySelector("#userName"); // 텍스트 필드 내용 가져오기
var newText = document.createTextNode(userName.value); // 새 텍스트 노드만들기
}
앞에서 만들어진 p요소 노드와 텍스트 노드를 만들기만 하고 연결해주질 않았으니 연결해줍시다.addendChild()함수를 사용해 텍스트 노드 newText를 요소 노드 newP의 자식 노드로 연결 합시다.
function newRegister() {
var newP = document.createElement("p"); // 새 p 요소 만들기
var userName = document.querySelector("#userName"); // 텍스트 필드 내용 가져오기
var newText = document.createTextNode(userName.value); // 새 텍스트 노드 만들기
newP.appendChild(newText);
}
지금까지 만든 <p> 태그는 <div id="nameList"></div> 안에 들어가야 된다. 다시 한번 appendChild()함수를 사용해 newP요소를 nameList 요소의 자식 노드로 연결하자.
function newRegister() {
var nameList = document.querySelector("#nameList"); //#nameList 가져옴
nameList.appendChild(newP);// newP노드를 nameLidt의 자식노드로 연결
userName.value = ""; // 다음 이름을 입력할 수 있도록 텍스트 필드 비우기
}
3. 웹 브라우저에서 확인하기
수정한 소스를 저장한 후 확인해보자. 우선 웹 개발자 도구 창의 [Element]탭을 엽니다. 탭의 소스를 보면 신청자 명단이 표시될 위치에 <div id="nameList"></div> 라고 표시되어 있어 그안에 내용은 없습니다. 텍스트필드에 이름을 입력하고 [신청]버튼을 눌러 보세요. 가로줄 바로 아래에 조금 전에 입력한 이름이 표시됩니다. [Element] 탭을 보면 <div> 태그안에 내용이 있습니다. <div>태그안에<p>태그가 만들어지고 그안에 위에서 입력한 이름이 추가되어 있을 것입니다. appendChild()함수는 자식 요소 중 맨 끝에 추가하는 것이기 때문에 최근에 입력한 이름이 맨 아래에 추가됩니다.
추가한 노드 순서 바꾸거나 삭제하기
참가 신청명단 프로그램 개선하기
1. 맨 위에 이름 추가하기
새로 추가하는 자식 노드를 기존 자식 노드보다 앞에 추가하기 위해서는 addendChild()함수대신 insertBefore()함수를 사용해 보겠습니다. 먼저 기존 소스 8번 줄 앞에 newP노드를 nameList노드의 맨 앞에 추가하는 소스입니다.
function newRegister() {
var nameList = document.querySelector("#nameList"); //#nameList 가져옴
nameList.inserBefore(nweP,nameList.ChildNodes[0]);//nameList.appendChild(newP); (newP노드를 nameLidt의 자식노드로 연결)
userName.value = ""; // 다음 이름을 입력할 수 있도록 텍스트 필드 비우기
}
2. 이름 삭제하기
이제 마지막으로 DOM트리에서 특정 노드를 삭제하는 방법을 사용해 명단에서 원하는 이름을 삭제해보겠습니다. 참가자 명단을 표시할 때 각 이름 오른쪽에 삭제 버튼을 함께 추가하려고 합니다. 이 버튼을 웹 문서에 추가한다면 HTML 태그 소스가 어떻게 될가요? 웹문서에 추가할 소스를 생각하며 여기서는 영어 x 대문자를 삭제버튼으로 활용합니다.
<span class = "del">X</span>
var newText = document.createTextNode(userName.value); // 새 텍스트 노드 만들기
newP.appendChild(newText); // 텍스트 노드를 p 요소의 자식 요소로 연결하기
var delBttn = document.createElement("span"); // 새 button 요소 만들기
var delText = document.createTextNode("X"); // 새 텍스트 노드 만들기
delBttn.setAttribute("class", "del"); // 버튼에 class 속성 설정하기
delBttn.appendChild(delText); // 텍스트 노드를 button 요소의 자식 요소로 연결하기
newP.appendChild(delBttn); // del 버튼을 p 요소의 자식 요소로 추가하기
var nameList = document.querySelector("#nameList");
수정한 소스를 저장한 후 웹브라우저에서 확인합니다.
x 버튼이 표시되고 마우스를 올리면 진해지고 내리면 연해집니다.
이제 삭제 버튼을 눌렀을 때 해당 이름을 삭제하는 함수를 작성해 보겠습니다. 우선 이름에 표시된 x버튼에 어떻게 접근해야 할까요? X 버튼을 추가할 때 class ="del" 속성을 함께 사용했으니 class 값을 식별자로 사용해 x버튼에 접근할 수 있습니다.
var removeBttns = document.querySelectorAll(".del");
x버튼을 눌렀을 때 어떤 노드를 삭제할 것인지 결정해야 합니다. X 버튼이 있는 소스부분의 DOM트리를 생각해 봅시다. span 노드에서 click 이벤트가 발생했을 때 삭제할 노드는 p 노드입니다. 그런데 노드 삭제는 부모 노드에서 해야하기 때문에 p노드를 삭제하려면 id ="nameLIst"인 div 노드에서 처리해야 합니다 . 즉 이벤트가 span노드에서 발생하면 removeChild()함수는 span노드의 '부모 노드의 부모 노드'에서 실행해야 합니다.
이제 addEvenListener()함수를 사용해 x버튼을 누르는 이벤트와 해당 이름을 삭제하는 함수를 연결하겠습니다.
앞에서 x 버튼에 접근한 값을 removeBttns 변수에 저장해놓았습니다. 여러 노드를 저장해야 함으로 x 버튼은 노드 리스트형태로 저장됩니다. for 문으로 removeBttns에 있는 노드 리스트 요소 전체를 반복해서 사용자가 i번째 버튼에 click 이벤트를 발생시켰을 때 실행할 함수를 연결합니다.
for (var i=0; i<removeBttns.length; i++) { // removeBttns에 있는 요소 전체를 반복
removeBttns[i].addEventListener("click", function() {
// i번째 버튼을 클릭했을 때 실행할 함수 선언
});
}
x버튼을 눌럿을 때 실행할 함수를 addEventList() 함수로 연결해 작성하겠습니다.
click 이벤트가 발생한 요소는 span노드인데 #nameList 요소에서 p노드를 삭제해야 하므로,
span 노드에서 parentNode.parentNode로 접근합니다. 다음 소스에서 this는 누른삭제 버튼을 가리킵니다.
for (var i=0; i<removeBttns.length; i++) { // removeBttns에 있는 요소 전체를 반복
removeBttns[i].addEventListener("click", function() { // i번째 버튼을 클릭했을 때 실행할 함수 선언
if (this.parentNode.parentNode) // 현재 노드(this)의 부모 노드의 부모 노드가 있을 경우 실행
this.parentNode.parentNode.removeChild(this.parentNode); // ‘현재 노드(this)의 부모 노드의 부모 노드’를 찾아 ‘현재 노드(this)의 부모 노드(p 노드)’ 삭제
});
}
}