[JavaScript] DOM & Event

wonyuuu·2022년 5월 22일
0

1. 노드에 접근하기

DOM (Document Object Model)

  • 문서 객체 모델
  • HTML 문서의의 각 요소들을 트리 형식으로 표현해줌
  • 각 객체를 노드라고 함

노드에 접근하기

  • document.querySelector() : 조건에 맞는 가장 첫 노드 하나만 가져옴
    • document.querySelector('h3:nth-of-type(2)') →이렇게 css의 가상 클래스 선택자와 비슷한 조건도 줄 수 있음
  • document.querySelector() : 여러 개의 노드 (NodeList 반환)
  • document.getElemenetsByTagName() : 여러 개의 노드 (HTMLCollection 반환)

2. 부모, 자식, 형제 노드

NodeList와 HTMLCollection

이름에서도 알 수 있듯이, NodeList는 모든 노드(요소 외에도 텍스트, 줄바꿈, 주석을 포함한 모든 노드) 를, HTMLCollection은 html 요소를 담는다.

const pList1 = document.querySelectorAll('p');
const pList2 = document.getElementsByTagName('p');

console.log(pList1);  // NodeList(4)  [p#first, p#second, p, p]
console.log(pList2);  // HTMLCollection(4) [p#first, p#second, p, p, first: p#first, second: p#second]

// 이 상태에서 p 태그를 추가하면 HTMLCollection에는 변경 사항이 실시간으로 반영됨

부모 노드에 접근

const red = document.getElementById('red');

// 2가지 방법
red.parentNode;
red.parentElement;

document.documentElement;  // HTML
document.documentElement.parentNode; // #document -> 부모 노드 중 모든 노드
document.documentElement.parentElement;  // null -> 부모 노드 중에 *요소* 노드(HTML 태그로 이루어진 것)만 반환

자식 노드에 접근

const ul = document.getElementById('color');

ul.childNodes;  // 자식 노드 전부
ul.children;  // 자식 노드 중에 *요소* 노드만

ul.firstChild;  // 첫번째 노드를 가져옴
ul.lastChild;

ul.firstElementChild;  // 첫번째 *요소* 노드를 가져옴
ul.lastElementChild;

형제 노드에 접근

const blue = doucument.getElementById('blue');

blue.previousSibling;  // 이전 노드
blue.nextSibling;

blue.previousElementSibling;  // 이전 *요소* 노드
blue.nextElementSibling

3. 노드 CRUD

노드 READ

// <li id="blue">Blue</li>

const blue = document.getElementById('blue');
blue.firstChild; // "Blue"

const blueTextNode = blue.firstChild;
blueTextNode.nodeName;  // '#text'
blueTextNode.nodeType;  // 3 (Text Node)
blueTextNode.nodeValue;  // 'Blue'

const ul = document.getElementById('color');
ul.nodeValue;  // null -> text node에서만 nodeValue를 이용해 수정 가능
ul.textContent;  // '\n     Red\n     \n     Blue\n     ' -> 가능은 하지만 마크업이 반영 안 됨
ul.innerHTML = '<li>RED</li>';  // -> 마크업까지 적용되지만 요소를 추가, 제거, 삭제할 때마다 String으로 작성해야 함

노드 CREATE

  • innerHTML을 사용하는 방법
    const newLi = document.createElement('li');
    newLi.innerHTML = 'green';
    ul.appendChild(newLi)
  • innerHTML을 사용하지 않는 방법
    const newLi2 = document.createElement('li');
    const newText = document.createTextNode('pink');
    newLi2 .appendChild(newText);
    ul.appendChild(newLi);  // appendChild는 항상 마지막 위치에 넣음
  • 원하는 위치에 추가하는 법
    // insertBefore : 특정 노드 이전에 추가
    const newLi3 = document.createElement('li');
    const newText3 = document.createTextNode('black');
    newLi3 .appendChild(newText3);
    ul.insertBefore(newLi3, red);  // red 앞에 li를 넣어라
  • appendChild , insertChild 에 기존 노드를 전달하면 해당 노드의 위치가 바뀜
  • 노드 복제
    const newBlack = newLi3.cloneNode();  // false와 같음 -> 노드 자신만 전달
    ul.appendChild(newBlack);
    
    const newBlack = newLi3.cloneNode(true);  // true 전달 시 깊은 복제 실행 (자식까지 모두 복제)
    ul.appendChild(newBlack);

노드 DELETE

ul.removeChild(newBlack);
ul.removeChild(ul.firstElementChild);
  • firstElementChild가 아닌 firstChild를 삭제한다면?
    ul.removeChild(ul.firstChild); : 요소 노드가 아니라 줄바꿈, 주석 등의 노드가 첫 자식이라면 의도와 달리 이런 노드를 삭제하게 됨

4. CSS styled, class 제어

  • 사용 방법
    • 요소.styled.css프로퍼티 = 값; 의 형태로 작성. 단, 프로퍼티는 camelCase 로 작성

      // ex.
      const box = document.getElementById('box');
      
      box.style.backgroundColor = 'red';
      box.style.color = '#fff';
      
      // 이렇게 하면 케밥 케이스 그대로도 사용 가능
      box.style["margin-left"] = '30px';
  • className에 접근하는 법
    • .className : 여러 개를 추가하고 싶다면 하나씩 적어줘야 함
      box.className = 'bg-red';
      box.className = 'bg-red txt-pink';
    • .classList
      // 추가
      box.classList.add('txt-white');
      box.classList.add('bg-green', 'txt-white');
      
      // 삭제
      box.classList.remove('txt white');
      
      // 변경
      box.classList.replace('bg-red', 'bg-blue');
      
      // 토글 (있으면 추가, 없으면 제거)
      box.classList.toggle('bg-red');

5. 이벤트 핸들러

  • JavaScript에서 작성하는 방법
    <body>
      <button type="button" id="btn">클릭3</button>
      <button type="button" id="btn2">클릭4</button>
      <script>
        function sayHello() {
          alert("hello");
        }
    		// 방법 1
        const btn = document.getElementById('btn');
        btn.onclick = sayHello;  // 괄호가 없어야 함 (반환값이 아니라 함수를 할당)
    		
    		// 방법 2
        const btn2 = document.getElementById('btn2');
        // btn2.addEventListener('click', sayHello);
        btn2.addEventListener('click', () => {
          alert("hi");
        });
      </script>
    </body>
    • 일부 이벤트는 addEventListener 로만 동작 ex) DOMContentLoaded
      → 가급적이면 addEventListener 사용
  • 자주 사용하는 이벤트
    • dblclick: 더블 클릭
    • focus: 인풋에 포커스가 있을 때
    • blur: 인풋 포커스를 잃을 때
    • mousemove: event 내의 clientX, clientY 값을 통해 마우스 포인터 위치 얻을 수 있음
    • resize: window에 대한 이벤트. 창 크기가 변할 때

6. 이벤트 버블링, 이벤트 위임

  • 자식 요소에서 발생한 이벤트 객체는 더 이상 부모 요소가 없을 때까지 부모 요소로 전파됨
    ⇒ 이벤트 버블링

    ```html
    <body>
      <div id="box">
        <ul id="list">
          <li id="color">Red</li>
        </ul>
      </div>
      <script>
        const box = document.getElementById("box");
        const list = document.getElementById("list");
        const item = document.getElementById("color");
    
        document.body.addEventListener('click', () => {
          console.log("1. body");
        })
        box.addEventListener('click', () => {
          console.log("2. box");
        })
        list.addEventListener('click', () => {
          console.log("3. list");
        })
        item.addEventListener('click', () => {
          console.log("4. item");
        })
      </script>
    </body>
    ```
  • ex) li 클릭 시

  • 버블링되지 않는 이벤트

    버블링 X버블링 O (동작은 같음)
    focusfocusin
    blurfocusout
    mouseentermouseover
    mouseleavemouseout
  • 이벤트 버블링을 막는 방법

    event.stopPropagation();
  • 이벤트 위임

    li 에 각각 클릭 이벤트를 달아준다면 요소가 100개일 경우, 100개의 EventListener를 작성해야 한다. 그런데 이벤트는 부모 요소로 버블링되므로 ul 에서 처리하면 하나의 EventListener만 작성할 수 있다. (부모 요소로 이벤트를 위임)


0개의 댓글