게으른 나에게

[코딩 자율학습 HTML + CSS + 자바스크립트] 3. 자바스크립트로 웹 동작 구현하기- "12장 문서 객체 모델과 이벤트 다루기" 본문

My Study/서적 공부

[코딩 자율학습 HTML + CSS + 자바스크립트] 3. 자바스크립트로 웹 동작 구현하기- "12장 문서 객체 모델과 이벤트 다루기"

handbefore 2024. 7. 26. 23:33

12.1 문서 객체 모델 이해하기

HTML 문법으로 작성한 태그, 속성, 주석, 텍스트와 같은 구성 요소들은 모두 웹 브라우저에서 각각 하나의 객체로 인식.

 

1.1 DOM(DOM, Document Object Model)

문서 객체 모델(DOM): HTML 구성 요소들을 다루는 객체. 웹 브라우저에 표시되는 HTML 문서 구조를 객체화한 모델 구조.

 

1.2 문서 객체 모델이 생성되는 방식

문서 객체 모델은 웹 브라우저가 HTML 문서를 해석하고,

해석한 HTML 문서 구조를 객체로 변환하는 방식으로 생성됨.

생성한 문서 객체 모델을 웹 브라우저에 표시.

웹 브라우저에 표시되는 HTML 문서는 내부적으로 문서 객체 모델을 해석해서 보이게 됨.

 

문서 객체 모델은 나무를 뒤집어 놓은 형태의 자료구조인 트리(tree) 구조를 가짐.    =>     "DOM 트리"

 

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document Object Model</title></head><body><h1>header</h1><a href="#">link</a></body></html>

앞의 HTML 문서를 해석하는 과정에서 문서 객체 모델을 생성. 이때 다음 그림처럼 DOM 트리 형태로 문서 구조를 변환.

DOM 트리는 document 객체 하위에 HTML 태그 요소, 속성, 텍스트, 주석 등이 트리 형태로 구성. 이들을 각각 노드(node)라고 함.

DOM 트리의 가장 꼭대기(최상위)에 있는 노드를 루트 노드(root node)라고 함. document는 노드가 아니라 객체이므로 여기서는 html이 루트 노드가 됨.

각 노드는 부모, 자식, 형제 관계 형성. 예를 들어, html 노드는 head 노드와 body 노드의 부모 노드. head 노드와 body 노드는 같은 레벨(level)에 있으므로 형제 노드, html 노드의 자식 노드.

 

DOM 생성을 보여 주기 위한 예제 코드는 줄 바꿈되지 않아서 보기 불편한 HTML 코드를 사용.  DOM을 생성할 때는 Enter 때문에 생긴 공백이 노드로 생성되어서 오히려 DOM을 이해하기 더 어렵게 함.

 

1.3 노드 타입 살펴보기

모든 노드가 똑같은 타입으로 생성되는 건 아님.

HTML 문법에서도 태그, 속성, 주석이 있는 것처럼 노드도 HTML 구성 요소에 따라 서로 다른 타입이 됨.

CSS와 관련 있는 노드 타입은 없음.

타입 설명
문서 노드(Node.DOCUMENT_NODE) 최상위 document 객체의 노드 타입
요소 노드(Node.ELEMENT_NODE) h1, p 태그와 같은 요소의 노드 타입
속성 노드(Node.ATTRIBUTE_NODE) href, src와 같은 속성의 노드 타입
텍스트 노드(Node.TEXT_NODE) 텍스트에 해당하는 노드 타입
주석 노드(Node.COMMENT_NODE) 주석에 해당하는 노드 타입

 

 


 

12.2 노드 선택하기

자바스크립트로 웹 브라우저에 표시되는 HTML 문서를 조작하려면 문서 객체 모델을 조작해야 함.

자바스크립트로 HTML 문서를 조작할 때 가장 먼저 할 일은 document 객체로 조작하려고 하는 문서 객체 모델의 노드를 선택. 노드는 문서 노드부터 주석 노드까지 여러 타입이 있지만, 자바스크립트는 주로 요소 노드를 선택해 조작함.

 

2.1 속성으로 노드 선택하기

document 객체는 트리를 탐색하면서 원하는 노드를 선택할 수 있는 속성을 제공. 

구분 속성 설명
모든 노드 탐색 parentNode 부모 노드를 반환합니다.
childNodes 모든 자식 노드를 반환합니다.
firstChild 첫 번째 자식 노드를 반환합니다.
lastChild 마지막 자식 노드를 반환합니다.
previousSibling 이전 형제 노드를 반환합니다.
nextSibling 다음 형제 노드를 반환합니다.
요소 노드 탐색 parentElement 부모 요소 노드를 반환합니다.
children 자식 요소 노드를 반환합니다.
firstElementChild 첫 번째 자식 요소 노드를 반환합니다.
lastElementChild 마지막 자식 요소 노드를 반환합니다.
previousElementSibling 이전 요소 노드를 반환합니다.
nextElementSibling 다음 요소 노드를 반환합니다.

 

2.2 메서드로 노드 선택하기

노드 탐색 속성으로 노드를 선택하는 방법은 노드의 타입을 가리지 않고 모든 노드를 이동하며 선택할 수 있다는 장점.

하지만 DOM 트리가 복잡할수록 원하는 노드를 찾아가기 어렵다는 단점.

그래서 일반적으로 요소 노드를 바로 선택할 수 있는 메서드를 이용한 노드 선택 방법과 적절하게 조합해서 사용.

 

 속성값과 태그명 사용하기 - get 메서드

메서드 형식 설명
getElementById(<id 속성값>) id 속성값과 일치하는 요소 노드를 1개만 선택합니다.
getElementsByClassName(<class 속성값>) class 속성값과 일치하는 요소 노드를 모두 선택합니다.
getElemenetsByTagName(<태그명>) 태그명과 일치하는 요소 노드를 모두 선택합니다.
<body>
  <h1 id="title">title</h1>
  <p class="text">text-1</p>
  <p class="text">text-2</p>
  <script>
    // id 속성값이 title인 요소 노드 1개 선택하기
    const el = document.getElementById("title");
    console.log(el); 
    // class 속성값이 text인 요소 노드 모두 선택하기
    const classEl = document.getElementsByClassName("text");
    console.log(classEl);
    // p 태그에 해당하는 요소 노드 모두 선택하기
    const tagEls = document.getElementsByName("p");
    console.log(tagEls);
  </script>
</body>

전체 코드를 실행하면 단일 요소 노드를 선택하는 getElementById() 메서드와 나머지 메서드의 차이점으로,

getElementById() 메서드로 선택하는 요소 노드는 무조건 1개이기 때문에 해당하는 요소 하나만을 보여줌. 다른 두 메서드는 HTMLCollection 객체로 여러 요소를 한꺼번에 선택.

여기서 HTMLCollection 객체는 유사 배열이라서 다음 코드처럼 배열의 인덱스로 요소에 하나씩 접근할 수 있음.

<script>
  const classEl = document.getElementsByClassName("text");
  console.log(classEl[0]);
  console.log(classEl[1]);
  const tagEls = document.getElementsByTagName("p");
  console.log(tagEls[0]);
  console.log(tagEls[1]);
</script>

출력 형태를 보면 마치 배열처럼 보이지만, 배열 자료형에는 없는 여러 객체 속성을 가지고 있음. 그래서 배열과 비슷하게 보임.

=>  "유사 배열"

객체 형태지만, 배열처럼 인덱스로 각각의 요소에 접근할 수 있음.

 

 CSS 선택자 사용하기 - query 메서드

메서드 형식 설명
querySelector(<CSS 선택자>) 매개변수로 넘어오는 CSS 선택자에 해당하는 노드를 1개만 선택합니다.
querySelectorAll(<CSS 선택자>) 매개변수로 넘어오는 CSS 선택자에 해당하는 노드를 모두 선택합니다.
<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>


class 속성값이 box-1인 요소 노드를 선택.
<script>
  const el = document.querySelector(".box-1");
</script>


class 속성값이 box-1인 요소의 하위에 있는 p 태그.
<script>
  const el = document.getElementsByClassName("box-1")[0].children;
  console.log(el);
</script>

<script>
  const el = document.querySelectorAll(".box-1 .text");
  console.log(el);
</script>

 

get 메서드와 query 메서드는 둘 다 원하는 요소 노드를 선택한다는 점은 같음.

하지만 query 메서드는 매개변수로 CSS 선택자를 전달받기 때문에 get 메서드보다 범용성이 더 좋음.

메서드의 성능은 단순하게 특정 매개변수만 전달받는 get 메서드가 > query 메서드보다 좋음.

그러나 현대적인 웹에서는 신경 쓰지 않아도 될 정도의 차이이므로 query 메서드를 사용하는 것이 더 나음.

 


 

12.3 노드 조작하기

document 객체의 속성이나 메서드로 문서 객체 모델의 노드를 선택하고 나면 선택한 노드에 여러 조작을 할 수 있음.

 

3.1 콘텐츠 조작하기

속성 설명
textContent 노드 요소의 모든 텍스트에 접근합니다.
innerText 노드 요소의 텍스트 중 웹 브라우저에 표시되는 텍스트에만 접근합니다.
innerHTML 노드 요소의 텍스트 중 HTML 태그를 포함한 텍스트에만 접근합니다.
<p id="title">Hello, <span style="display:none;">Javascript!</span></p>

document.getElementById("title").textContent; // Hello, Javascript!
document.getElementById("title").innerText;  // Hello,
document.getElementById("title").innerHTML;  // Hello, <span style="display: none;">Javascript!</span>

 

콘텐츠 조작 속성은 접근한 노드의 콘텐츠를 가져올 뿐만 아니라 속성에 값을 할당하면 각 노드의 콘텐츠를 바꿀 수도 있음.

<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>

 

3.2 스타일 조작하기

선택된 노드의 타입이 요소 노드라면 style 속성으로 요소에 스타일(CSS)을 지정할 수 있음.

<노드>.style.<css 속성명> = <속성값>;
p 태그의 텍스트 색상을 빨간색으로 변경.

<p id="text">text</p>
<script>
  const pEl = document.querySelector("p"); // 노드 선택하기
  pEl.style.color = "red";
</script>

CSS 속성 중에서 background-color 속성과 같이 속성명에 대시(-)가 있는 속성은 자바스크립트에서 -를 뺄셈 연산자(-)로 인식.

그러므로 backgroundColor처럼 카멜 표기법으로 변경해서 작성.

 

3.3 클래스 속성 조작하기

class 속성을 조작해 스타일을 적용할 수 있음. 선택한 요소 노드에 class 속성을 지정할 때는 classList 속성의 add(), remove(), toggle() 메서드를 사용.
<노드>.classList.add("class 속성값"); // 추가
<노드>.classList.remove("class 속성값"); // 삭제
<노드>.classList.toggle("class 속성값"); // 추가와 삭제 반복

 

3.4 데이터 속성 조작하기

HTML5에서 새로 추가된 data-* 속성. HTML 문법에서 사용할 수 있는 속성 외에 사용자가 원하는 속성을 추가할 수 있게 한 사용자 정의(custom) 속성. data-* 속성은 자바스크립트의 dataset 속성을 사용해 조작. dataset 속성은 HTML 문서에서 data-* 속성을 가져오거나 지정.

data-* 속성이 적용된 HTML 요소 노드를 선택해 data 속성값을 출력.

<button data-cnt="10">가방 구매</button>
<button data-cnt="0">신발 구매</button>
<script>
  const buttonEls = document.querySelectorAll("button");
  buttonEls.forEach((el) => {
    console.log(el.dataset);
  })
</script>

단일 노드만 선택해 조작. 

 

querySelectorAll() 메서드로 복수의 노드를 선택하는 방법으로 코드를 작성. 

querySelectorAll() 메서드로 button 태그에 해당하는 노드를 한 번에 선택. 그리고 forEach() 메서드로 반복해서 각 노드에 접근한 뒤, dataset 속성으로 data-cnt 속성 정보를 가져와 출력.

 

dataset 속성으로 노드의 data-* 속성에 대한 정보를 가져오고 이 정보가 DOMStringMap 객체에 담겨 반환. 이 중에서 정확하게 data-cnt 속성의 값만 가져오고 싶으면 다음처럼 객체 속성에 접근하는 방법을 사용.

<script>
  const buttonEls = document.querySelectorAll("button");
  buttonEls.forEach((el) => {
    console.log(el.dataset.cnt);
  })
</script>


실행결과
10
0

 

data-cnt 속성의 값을 바꿈.

<script>
  const buttonEls = document.querySelectorAll("button");
  buttonEls.forEach((el) => {
    el.dataset.cnt = 50;
  })
</script>
 

3.5 메서드로 속성 조작하기

모든 속성을 전체적으로 조작

메서드 형식 설명
<노드>.getAttribute("속성명"); 속성값을 가져옵니다.
<노드>.setAttribute("속성명", "속성값"); 속성값을 설정합니다.
<노드>.remoteAttribute("속성명"); 속성을 삭제합니다.
getAttribute() 선택된 요소 노드의 속성값을 가져오고 싶을 때 사용.

<a href="https://www.gilbut.co.kr">길벗</a>
<script>
  const aEl = document.querySelector("a");
  const href = aEl.getAttribute("href");
  console.log(href);
</script>


속성값을 새로 설정하고 싶을 때는 setAttribute() 메서드를 사용.
<a href="https://www.gilbut.co.kr">길벗</a>
<script>
  const aEl = document.querySelector("a");
  const href = aEl.getAttribute("href");
  aEl.setAttribute("href", "https://www.sucoding.kr");
  aEl.innerText = "수코딩";
</script>


바꾼 속성값을 적용해 새 창으로 열기.
<a href="https://www.gilbut.co.kr">길벗</a>
<script>
  const aEl = document.querySelector("a");
  const href = aEl.getAttribute("href");
  aEl.setAttribute("href", "https://www.sucoding.kr");
  aEl.innerText = "수코딩";
  aEl.setAttribute("target", "_blank");
</script>


removeAttribute() 메서드를 사용하면 요소 노드의 속성을 제거.
<a href="https://www.gilbut.co.kr" class="red-color">길벗</a>
<script>
  const aEl = document.querySelector("a");
  aEl.removeAttribute("class"); // class 속성 삭제
</script>

 

getAttribute() 메서드와 setAttribute() 메서드는 모든 속성의 상위 메서드라서 classList 속성이나 dataset 속성으로 하는 조작을 전부 할 수 있음.

<style>
  .red-color{
    color:red;
  }
</style>
(중략)
<a href="https://www.gilbut.co.kr" data-link="길벗">길벗</a>
<script>
  const aEl = document.querySelector("a");
  aEl.setAttribute("data-link", "이지톡");
  aEl.setAttribute("class", "red-color");
</script>

 

classList 속성 vs setAttribute() 메서드

classList 속성으로 class 속성값을 추가하거나 삭제하면 기존 요소가 가지고 있던 class 속성값을 보존하면서 추가하거나 삭제한다는 특징.  a 태그에 class 속성이 이미 있었다면 여기에 단순히 추가되는 형태로 코드가 작동.

<a href="#" class="fz20">link</a>
<script>
  const aEl = document.querySelector("a");
  // a 태그의 기존 class 속성값을 보존하면서 red-color 값 추가
  aEl.classList.add("red-color");
</script>

실행결과
<a href="#" class="fz20 red-color">link</a>


하지만 setAttribute() 메서드는 아예 속성값을 새로 설정하는 것이어서 기존 class 속성값을 보존하지 않음.


<a href="#" class="fz20">link</a>
<script>
  const aEl = document.querySelector("a");
  // a 태그의 기존 class 속성값을 보존하지 않고 red-color 값 설정
  aEl.setAttribute("red-color");
</script>

실행결과
<a href="#" class="red-color">link</a>
이는 classList 속성의 remove() 메서드와 removeAttribute() 메서드에서도 똑같음.

remove() 메서드는 기존 속성을 보존하면서 매개변수로 전달된 속성만 삭제.
removeAttribute() 메서드는 속성 자체를 삭제.

 

 


 

12.4 노드 추가 / 삭제하기

DOM 트리에서 새로운 노드를 생성하고, 생성한 노드를 기존 DOM 트리와 연결하면 동적으로 새로운 요소를 화면에 추가할 수 있음.

 

4.1 노드 추가하기

새로운 요소를 화면에 추가하려면 먼저 DOM 트리에 새로운 노드를 생성. 생성한 노드를 기존의 DOM 트리 노드와 연결.

구분 메서드 설명
노드 생성 createElement() 요소 노드를 생성합니다.
createTextNode() 텍스트 노드를 생성합니다.
createAttribute() 속성 노드를 생성합니다.
노드 연결 <기준 노드>.appendChild(<자식 노드>) 기준 노드에 자식 노드를 연결합니다.
<기준 노드>.setAttributeNode(<속성 노드>) 기준 노드에 속성 노드를 연결합니다.

 

 

노드 추가.

<!DOCTYPE html>
<html>
<head>
  <title>Create Node</title>
</head>
<body>
  <script></script>
</body>
</html>

 

<!DOCTYPE html>
<html>
<head>
  <title>Create Node</title>
</head>
<body>
  <script></script>
</body>
</html>

<script>
  // 요소 노드 생성하기
  const aEl = document.createElement("a"); 
</script>

 

생성된 노드를 기존 DOM 트리와 연결. 기존 노드에 자식 노드로 연결하므로 appendChild() 메서드를 사용. appendChild() 메서드의 매개변수에 생성한 노드를 넘겨주면 됨.

앞에서 생성한 a 요소 노드를 body 요소 노드의 자식 노드로 연결. DOM에서 제공하는 body 속성을 사용하면 body 요소 노드에 바로 접근.

 

단순하게 요소 노드만 연결했기 때문에 웹 브라우저에는 아무것도 보이지 않음. 텍스트 노드도 함께 연결.

지금코드 a 요소 노드가 하나밖에 없으니 텍스트 노드를 생성한 뒤, querySelector() 메서드로 a 요소 노드를 선택해 appendChild() 메서드로 연결.

<script>
  (중략)
  // 텍스트 노드 추가하기
  const txtEl = document.createTextNode("길벗"); 
  document.querySelector("a").appendChild(txtEl);
</script>

 

 

hn, p, span, i 태그처럼 일반적으로 텍스트가 필요한 요소들은 이렇게 텍스트 노드만 생성하고 연결해도 충분.

하지만 a 태그나 img 태그처럼 별도의 속성이 필요한 요소들은 텍스트 노드만으로 충분하지 않음. (a 태그에는 href 속성, target 속성 등)속성이 포함된 요소들은 속성 노드까지 생성해 연결해야 함.

<script>
  (중략)
  // href 속성 노드 추가하기
  const hrefAttr = document.createAttribute("href");
  hrefAttr.value = "https://www.gilbut.co.kr";
  document.querySelector("a").setAttributeNode(hrefAttr);
</script>

생성된 속성 노드에 값을 추가할 때는 속성 노드의 value 속성에 값을 할당. 마지막으로, 생성한 속성 노드를 setAttributeNode() 메서드로 요소 노드와 연결.

속성 노드는 a 요소 노드의 자식 노드로 추가하는 것이 아니라는 점에 주의.

속성 노드까지 연결하면 이제 a 요소 노드는 a 태그의 기능을 하게 됩니다. 그래서 텍스트를 클릭하면 길벗 사이트로 정상적으로 이동.

 

4.2 노드 삭제하기

노드를 삭제할 때는 removeChild() 메서드. removeChild() 메서드는 부모 노드에 연결된 자식 노드를 삭제.

<부모 노드>.removeChild(<자식 노드>)
<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>

p 요소 노드를 찾아서 삭제.
삭제 노드는 항상 부모 노드에서 removeChild() 메서드를 사용.
부모 노드를 반환하는 parentNode 속성으로 부모 노드에 접근해서 삭제.
 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>

 

 


 

12.5 폼 조작하기

5.1 form 태그 선택하기

HTML 폼 요소의 시작은 항상 form 태그.

form 태그는 forms 속성과 name 속성으로 선택할 수 있음.

 

 forms 속성 사용하기

document 객체의 forms 속성은 모든 form 태그의 노드 정보를 HTMLCollection 객체에 담아 반환.  forms 속성을 사용하면 화면에 있는 form 요소 노드를 쉽게 선택.

<body>
  <form>
    <input type="text" name="userid">
  </form>
  <form>
    <input type="text" name="username">
  </form>
  <form>
    <input type="text" name="usernick">
  </form>
</body>

HTMLCollection 객체는 유사 배열이라서 인덱스를 사용해 form 요소 노드에 하나씩 접근.
forms 속성을 사용하는 방법은 form 태그의 위치가 바뀌면 잘못 참조하게 되어 예기치 않게 오류가 발생할 수 있다는 단점.

 

 

 name 속성 사용하기

form 태그에 name 속성을 사용하면 forms 속성보다 훨씬 직관적으로 form 요소 노드를 선택할 수 있음.

<body>
  <form name="frm1">
    <input type="text">
  </form>
  <form name="frm2">
    <input type="text">
  </form>
  <form name="frm3">
    <input type="text">
  </form>
</body>

form 태그에 name 속성이 추가되면 다음과 같이 name 속성값으로 form 요소 노드에 접근할 수 있음.

document.frm1; // form 태그의 name 속성값이 frm1인 노드
document.frm2; // form 태그의 name 속성값이 frm2인 노드
document.frm3; // form 태그의 name 속성값이 frm3인 노드

name 속성값으로 접근하면 form 태그의 순서가 바뀌어도 문제가 발생하지 않음.

 

5.2 폼 요소 선택하기

폼 요소에는 input 태그를 비롯해 select 태그, button 태그 등이 있음.

이런 폼 요소를 선택할 때는 elements 속성이나 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>

elements 속성은 form 요소 노드의 하위 노드 중 폼 요소 노드만 반환하는 속성.

elements 속성 HTMLFormControlsCollection 객체에 여러 개의 노드를 담아 반환. HTMLFormControlsCollection 객체에는 form 요소 노드의 하위에 있는 폼 요소 노드의 정보가 담겨 있음. 인덱스로 정의된 폼 요소 노드의 정보는 기본으로 포함되는 값.

앞의 예제 코드처럼 폼 요소에 name 속성을 사용했다면 name 속성값으로도 노드를 참조할 수 있게 데이터가 정의.

=> 폼 요소에 접근할 때는 인덱스를 사용하는 방법 name 속성값을 사용하는 방법 중 하나를 선택할 수 있음.

 

5.3 폼 요소의 입력값 다루기

폼 요소는 사용자에게 값을 입력받아 이를 서버에 전달. 서버에 전달하기까지 폼 요소에 입력된 값이 유효한지는 검증할 수 있어야 함.

사용자에게 값을 입력받는 폼 요소: input 태그, select 태그

 

 한 줄 입력 요소 다루기

input 태그의 type 속성값을 text, password, number, url, search, email 등으로 지정했을 때 표시되는 폼 요소.

<form name="frm">
  <input type="text" name="id">
  <input type="password" name="pw">
</form>

text와 password 요소에 사용자가 입력한 값을 가져오려면 해당 요소 노드에서 value 속성을 사용.
document.frm.id.value;
document.frm.pw.value;

웹 사이트에 회원가입할 때, 웹 브라우저에는 입력한 값암호화되어 보이는데, value 속성이 사용. 

value 속성을 사용하면 웹 브라우저에 입력한 값을 그대로 가져올 수 있어서 이를 검증할 수 있음.

value 속성에 값을 할당해 원하는 값을 자바스크립트로 입력 요소에 직접 삽입.

<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>

 

 여러 줄 입력 요소 다루기

textarea 태그를 사용하면 표시되는 폼 요소.

<form name="frm">
  <textarea name="desc"></textarea>
</form>

value 속성에 값을 할당한 자바스크립트 코드를 추가.

<form name="frm">
  <textarea name="desc"></textarea>
</form>
<script>
  document.frm.desc.value = 'setting!';
</script>

 

 체크박스 다루기

<form>
  <label><input type="checkbox" value="apple">사과</label>
  <label><input type="checkbox" value="banana">바나나</label>
  <label><input type="checkbox" value="orange">오렌지</label>
  <label><input type="checkbox" value="melon">멜론</label>
</form>

체크박스에 체크 표시가 있는지는 checked 속성으로 확인. 
반복문으로 체크박스 노드에 하나씩 접근한 뒤에 checked 속성이 있는지 확인. 
만약 있으면 value 속성으로 값을 가져오면 됨.

const checkboxEls = document.querySelectorAll("[type='checkbox']");
for(let i = 0; i < checkboxEls.length; i++){
  if(checkboxEls[i].checked === true){
    console.log(checkboxEls[i].value);
  }
}

웹 브라우저로 예제 코드를 실행한 뒤 원하는 항목에 체크 표시. 
앞에서 작성한 자바스크립트 코드를 콘솔창에 입력하고 실행하면 체크한 항목의 값이 출력.

체크박스를 모두 체크된 상태로 바꾸고 싶다면 자바스크립트로 checked 속성에 true를 할당하.

<form>
  <label><input type="checkbox" value="apple">사과</label>
  <label><input type="checkbox" value="banana">바나나</label>
  <label><input type="checkbox" value="orange">오렌지</label>
  <label><input type="checkbox" value="melon">멜론</label>
</form>
<script>
  const checkboxEls = document.querySelectorAll("[type='checkbox']");
  for(let i = 0; i < checkboxEls.length; i++){
    checkboxEls[i].checked = true;
  }
</script>

 

 라디오버튼 다루기

<form>
  <label><input type="radio" name="fruits" value="apple">사과</label>
  <label><input type="radio" name="fruits" value="banana">바나나</label>
  <label><input type="radio" name="fruits" value="orange">오렌지</label>
  <label><input type="radio" name="fruits" value="melon">멜론</label>
</form>

const radioEls = document.querySelectorAll("[type='radio']");
for(let i = 0; i < radioEls.length; i++){
  if(radioEls[i].checked === true){
    console.log(radioEls[i].value);
  }
}

라디오버튼은 여러 개를 선택하는 요소가 아니므로 다음처럼 원하는 항목만 선택될 수 있게 if 문으로 처리.

<form>
  (중략)
</form>
<script>
  const radioEls = document.querySelectorAll("[type='radio']");
  for(let i = 0; i < radioEls.length; i++){
    if(radioEls[i].value === 'banana'){
      radioEls[i].checked = true;
    }
  }
</script>

 

 콤보박스 다루기

selected 속성으로 선택 항목을 확인.

<form>
  <select>
    <option value="apple">사과</option>
    <option value="banana">바나나</option>
    <option value="orange">오렌지</option>
    <option value="melon">멜론</option>
  </select>
</form>

const optionEls = document.querySelectorAll("option");
for(let i = 0; i < optionEls.length; i++){
  if(optionEls[i].selected === true){
    console.log(optionEls[i].value);
  }
}

웹 브라우저로 실행한 뒤 원하는 항목을 선택.
현재 선택된 콤보박스의 value 속성값을 결과로 가져옴.

const optionEls = document.querySelectorAll("option");
for(let i = 0; i < optionEls.length; i++){
  if(optionEls[i].selected === true){
    console.log(optionEls[i].value);
  }
}

<form>
  (중략)
</form>
<script>
  const optionEls = document.querySelectorAll("option");
  for(let i = 0; i < optionEls.length; i++){
    if(optionEls[i].value === 'banana'){
      optionEls[i].selected = true;
    } 
  }

 

 파일 업로드 요소 다루기

input 태그의 type 속성값을 file로 지정하면 표시되는 요소.

<form name="frm">
  <input type="file" name="upload">
</form>

파일 업로드 요소에서 핵심은 files 속성으로 반환되는 FileList 객체.

const filesObj = document.frm.upload.files;
console.log(filesObj);

결과로 FileList 객체가 반환.
FileList 객체는 파일 업로드 요소로 선택한 파일에 대한 다양한 정보를 담고 있는 객체.

FileList 객체의 속성에 접근하면 다음과 같은 여러 정보를 가져올 수 있음.

const files = document.frm.upload.files;
files[0].name; // 파일 이름
files[0].size; // 파일 크기
files[0].type; // 파일 타입
files[0].lastModifiedDate; // 파일 마지막 수정일

 

폼 요소 관련 기타 메서드

메서드 설명
submit() 폼 요소의 값을 전송(submit)합니다.
focus() 폼 요소에 포커스(커서)를 이동합니다.

 

 


 

12.6 이벤트 다루기

이벤트(event)웹 브라우저와 사용자 사이에 상호작용이 발생하는 특정 시점을 의미.

 

6.1 이벤트 종류

구분 이벤트 설명
마우스 이벤트 onclick 마우스로 클릭하면 발생합니다.
ondblclick 마우스로 두 번 빠르게 클릭하면 발생합니다.
onmouseover 마우스 포인터를 올리면 발생합니다.
onmouseout 마우스 포인터가 빠져나가면 발생합니다.
마우스 이벤트 onmousemove 마우스 포인터가 움직이면 발생합니다.
onwheel 마우스 휠(wheel)을 움직이면 발생합니다.
키보드 이벤트 onkeypress 키보드 버튼을 누르고 있는 동안 발생합니다.
onkeydown 키보드 버튼을 누른 순간 발생합니다.
onkeyup 키보드 버튼을 눌렀다가 뗀 순간 발생합니다.
포커스 이벤트 onfocus 요소에 포커스가 되면 발생합니다.
onblur 요소가 포커스를 잃으면 발생합니다.
폼 이벤트 onsubmit 폼이 전송될 때 발생합니다.
리소스 이벤트 onload 웹 브라우저의 리소스 로드가 끝나면 발생합니다.

 

6.2 이벤트 등록하기

이벤트가 발생할 때 어떤 작업을 할지 자바스크립트 코드로 작성하는 것.

 

 인라인 방식으로 이벤트 등록하기

HTML 태그에 속성으로 이벤트를 등록하는 방법.

onclick 이벤트를 button 태그의 속성으로 사용.
속성값으로는 이벤트가 발생할 때 실행될 함수를 지정.
버튼을 클릭해 보면 clickEvent() 함수가 실행되어 웹 브라우저에 경고창이 출력/

<button onclick="clickEvent()">클릭</button>
<script>
  function clickEvent(){
    alert("click");
  }
</script>
입력창을 클릭해서 커서를 활성화하면 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() 메서드를 사용하면 안 됨.

경고창을 클릭하는 순간 입력창에서 커서가 빠져나갔다고 판단해 onblur 이벤트가 발생. 경고창이 닫히면 다시 커서가 입력창으로 들어가서 onfocus 이벤트가 발생. 따라서 경고창이 무한으로 뜨는 현상이 발생.

 

 프로퍼티 리스너 방식으로 이벤트 등록하기

요소 노드에 직접 속성으로 이벤트를 등록하는 방법.

<button>클릭</button>
<script>
  const btnEl = document.querySelector("button");
  btnEl.onclick = function(){
    alert("click");
  }
</script>

 

 이벤트 등록 메서드로 이벤트 등록하기

 addEventListener() 메서드를 사용해 이벤트를 등록.

<노드>.addEventListener("<이벤트 타입>", <이벤트 함수>);
<button>클릭</button>
<script>
  const btnEl = document.querySelector("button");
  btnEl.addEventListener("click", function(){
    alert("button Click");
  });
</script>

※함수 표현식으로 정의된 함수는 호이스팅에 의해 선언과 할당이 분리되므로 참조하려는 함수가 addEventListener() 메서드보다 반드시 위에 작성되어야 함.

 


 

12.7 이벤트 객체와 this

이벤트 타입에 따라 발생하는 이벤트의 각종 정보가 들어 있는 객체 집합.

이벤트 객체는 개발자가 직접 생성하는 것이 아니라 이벤트가 발생하면 실행되는 함수의 매개변수로 같이 전달.

 

7.1 이벤트 객체 사용하기

이벤트가 발생하면 실행되는 함수에는 내부적으로 이벤트 객체가 매개변수로 전달.

 

 PointerEvent 객체의 주요 속성

속성 설명
clientX 마우스가 클릭된 x좌표(수평 스크롤 포함 X)
clientY 마우스가 클릭된 y좌표(수직 스크롤 포함 X)
pageX 마우스가 클릭된 x좌표(수평 스크롤 포함 O)
pageY 마우스가 클릭된 y좌표(수직 스크롤 포함 O)
screenX 모니터의 왼쪽 위 모서리를 기준으로 마우스가 클릭된 x좌표
screenY 모니터의 왼쪽 위 모서리를 기준으로 마우스가 클릭된 y좌표
<button>클릭</button>
<script>
  const btnEl = document.querySelector("button");
  btnEl.addEventListener("click", function(event){ // 이벤트 객체
    console.log(`clientX:${event.clientX}`);
    console.log(`clientY:${event.clientY}`);
    console.log(`pageX:${event.pageX}`);
    console.log(`pageY:${event.pageY}`);
    console.log(`screenX:${event.screenX}`);
    console.log(`screenY:${event.screenY}`);
  })
</script>

 

KeyboardEvent 객체의 주요 속성

속성 설명
keyCode 키보드에서 눌린 키의 유니코드 값을 반환합니다.
ctrlKey Ctrl 키가 눌렸으면 true, 그렇지 않으면 false를 반환합니다.
altKey Alt 키가 눌렸으면 true, 그렇지 않으면 false를 반환합니다.
shiftKey Shift 키가 눌렸으면 true, 그렇지 않으면 false를 반환합니다.
<form>
  <input type="text">
</form>
<script>
  const inputEl = document.querySelector("input");
  inputEl.addEventListener("keydown", function(event){ // 이벤트 객체
    console.log(`keyCode:${event.keyCode}`);
    console.log(`ctrlKey:${event.ctrlKey}`);
    console.log(`altKey:${event.altKey}`);
    console.log(`shiftKey:${event.shiftKey}`);
  })
</script>

 

7.2 이벤트 취소하기

HTML 태그 중 일부는 기본으로 이벤트가 적용. (a 태그와 form 태그).

a 태그는 생성된 요소를 클릭하면 다른 페이지로 이동하도록 클릭 이벤트가 연결된 상태.

form 태그는 폼 내부에서 버튼이 눌리면 전송되도록 전송 이벤트가 연결된 상태.

 

preventDefault() 메서드를 사용하면 태그에 기본으로 연결된 이벤트를 취소.

2개의 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>

 

7.3 this 키워드 사용하기

함수 내부에서 this 키워드를 사용하면 이벤트가 발생한 요소 노드를 바로 가리킬 수 있음.

<p>text-1</p>
<p>text-2</p>
<p>text-3</p>
<script>
  const pEls = document.querySelectorAll("p");
  pEls.forEach((el) => {
    el.addEventListener("click", function(){
      console.log(this);
    });
  })
</script>

p 태그를 클릭하면 텍스트 색상을 빨간색으로 바꾸고, 이미 빨간색이라면 다시 검은색으로 바꾸도록 코드를 변경.

<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';
      }
    });
  })
</script>

이벤트 함수를 화살표 함수로 작성하면 this의 범위가 달라져서 this가 이벤트 발생 노드를 가리키지 않음.

 

 

 


출처

https://www.gilbut.co.kr/book/view?bookcode=BN003377

 

코딩 자율학습 HTML + CSS + 자바스크립트

기초부터 반응형 웹까지 초보자를 위한 웹 개발 입문서

www.gilbut.co.kr