[elice] DOM, 이벤트

yuna·2023년 5월 25일
0

elice

목록 보기
1/14
post-thumbnail

📌 객체와 함수

객체? 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조이다. 객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.

객체 프로퍼티 접근 하는 방법은 2가지가 있다.

  • 마침표 표기법 : .
  • 대괄호 표기법 : []
const person = {
  firstName : "Yu-Na",
  "last-name" : "park",
  1 : 10
};

person.firstName  // Yu-na  
person["last-name"]  // park

원시값 vs 객체

  • 원시값은 변경 불가능한 값이고 객체는 변경 가능한 값이다.
  • 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장되며
    객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.
  • 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달(pass by value)이라 한다.
    반면 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달 된다. 이를 참조에 의한 전달(pass by reference)이라 한다.

함수? 입력을 받아 출력을 내보내는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의
실행 단위로 정의한 것 이다. 함수는 객체이지만 일반 객체와 달리 함수는 호출할 수 있고, 함수 객체의 고유한 프로퍼티를 가진다.

즉시 실행 함수 는 단 한번만 호출되며 다시 호출할 수 없다. 함수의 이름이 없는 익명 함수를 사용하는 것이 일반적이다.

let result = (function () {
  let a = 4;
  let b = 8;
  return a * b;
})();

재귀 함수 함수가 자기 자신을 호출한다. 재귀 함수는 자신을 무한 재귀 호출하기 때문에 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 한다.

function recusion(n) {
  if(n < 0) return;
  console.log(n);
  recusion(n - 1);
}

recusion(10);

중첩 함수 함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다. 그리고 중첩 함수를 포함하는 함수는 외부 함수라 부른다. 중첩 함수는 스코프클로저에 깊은 관련이 있다.

function outer(n) {
  let x = 1;
  
  function inner() {
    let y = 2;
    console.log(x + y);
  }
  inner();
}

outer();

recusion(10);

콜백 함수 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수이다.

function repeat(n, callback) {
  for(let i=0; i<n; i++){
    callback(i);
  }
}

const log = function(i) {
  console.log(i);
}

repeat(5, log);

📢 DOM의 구조 및 개념

브라우저의 렌더링 과정 렌더링이란 HTML, CSS, javascript로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것이다.

  1. 브라우저는 렌더링에 필요한 리소스(HTML, CSS, JS 등)를 요청하고 서버로부터 응답을 받음.
  2. 브라우저의 렌더링 엔진은 응답된 HTML과 CSS를 파싱하여 DOMCSSOM을 생성하고 이들을 결합하여 렌더 트리(Render Tree)를 생성한다.
  3. 브라우저의 자바스크립트 엔진은 응답된 자바스크립트를 파싱하여 AST(Abstract Syntax Tree)를 생성하고, 바이트코드로 변환하여 실행한다. (이때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합된다.)
  4. 렌더 트리를 기반으로 HTML 요소의 레이아웃을 계산하고 브라우저 화면에 HTML 요소를 페인팅한다.

DOM(Document Object Model) HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API이자, 프로퍼티와 메서드를 제공하는 트리 자료 구조다.

노드 객체 타입 DOM은 노드 객체들로 구성된 트리 자료구조를 말하며, DOM 트리라고도 불린다.
문서 노드 요소 노드 어트리뷰트 노드 텍스트 노드 타입이 중요!

DOM API - 요소 노드 취득할 수 있는 방법은 크게 4가지로 나뉜다.

  1. id를 이용한 요소 노드 취득 : document.getElementById('id')
  2. 태그 이름을 이용한 요소 노드 취득 : document.getElementsByTagName('tag')
  3. class을 이용한 요소 노드 취득 : document.getElementsByClassName('class')
  4. CSS 선택자를 이용한 요소 노드 취득 : document.querySelector("# .') / document.querySelectorAll('# .')

HTMLCollection vs NodeList HTMLCollection과 NodeList를 구분하는 중요한 특징은 노드 객체의 상태 변화를 실시간으로 반영하는 살아 있는 객체라는 점이다. -> iterable 객체

// HTMLCollection
<style>
    .red {
    	color: red;
    }
    .blue {
    	color: blue;
    }
</style>

<body>
    <ul id="fruits">
        <li class="red">Apple</li>
        <li class="red">Banana</li>
        <li class="red">Orange</li>
    </ul>
  
  	<script>
      // class 값이 'red'인 요소 노드를 모두 탐색하여 HTMLCollection 객체에 담아 반환한다.
      const $elems = document.getElementsByClassName("red");
      // 이 시점에 HTMLCollection 객체에는 3개의 요소 노드가 담겨 있다.
      console.log($elems); // HTMLCollection(3) [li.red, li.red, li.red]

      // HTMLCollection 객체의 모든 요소의 class 값을 blue로 변경한다.
      for (let i = 0; i < $elems.length; i++) {
        $elems[i].className = "blue";
      }

      // HTMLCollection 객체의 요소가 3개에서 1개로 변경되었다.
      console.log($elems);

      // 유사 배열 객체이면서 이터러블인 HTMLCollection을 배열로 변환하여 순회
      [...$elems].forEach((elem) => (elem.className = "blue"));
    </script>
</body>

노드 탐색

  • parentNode, previousSibling, firstChild, childNodes 프로퍼티(Node.prototype)
  • previousElementSibling, nextElementSibling과 children(Element.prototype

DOM 조작

  1. innerHTML 프로퍼티 : Element.prototype.innerHTML 프로퍼티는 요소 노드의 HTML 마크업을 취득하거나 변경하며 HTML 마크업을 문자열(string)로 반환한다. 텍스트만 가져오는 Node.prototype.textContent 프로퍼티도 있다.
    요소 노드의 innerHTML 프로퍼티에 문자열을 할당하면 요소 노드의 모든 자식 노드가 제거되고 할당한 문자열에 포함되어 있는 HTML 마크업이 파싱되어 요소 노드의 자식 노드로 DOM에 반영된다. innerHTML 프로퍼티는 복잡하지 않은 요소를 새롭게 추가할 때 유용하지만 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입해야 할 때는 사용하지 않는 것이 좋다.

  2. insertAdjacentHTML 메서드 : Element.prototype.insertAdjacentHTML 메서드는 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입한다. 두 번째 인수로 전달한 HTML 마크업 문자열(DOMString)을 파싱하고 그 결과로 생성된 노드를 첫 번째 인수로 전달한 위치(position)에 삽입하여 DOM에 반영한다. 첫 번째 인수로 전달할 수 있는 문자열은 beforebegin(태그앞), afterbegin(텍스트앞), beforeend(텍스트뒤), afterend(태그뒤)있다. insertAdjacentHTML 메서드는 기존 요소에는 영향을 주지 않고 새롭게 삽입될 요소만을 파싱하여 자식 요소로 추가하므로 innerHTML 프로퍼티보다 효율적이고 빠르다.

  3. 노드 생성 및 추가, 노드 삽입 : 요소 노드 생성은 Document.prototype.createElement(tagName) 메서드를 사용하며 텍스트 노드 생성은 Document.prototype.createTextNode(text) 메서드를 사용한다. 텍스트 노드를 요소 노드의 자식 노드로 추가하기 위해서는 Node.prototype.appendChild(childNode)메서드를 사용한다.

let $container = document.getElementById('container');
let $div = document.createElement('div');
let $text = document.createTextNode('hi');

$div.appendChild($text);
$container.appendChild($div);
  1. 노드 복사 교체, 삭제

어트리뷰트 노드
HTML 요소의 시작 태그(start/opening tag)에 어트리뷰트 이름=“어트리뷰트 값” 형식으로 정의한다.
글로벌 어트리뷰트(id, class, style, title, lang, tabindex, draggable, hidden 등)와 이벤트 핸
들러 어트리뷰트(onclick, onchange, onfocus, onblur, oninput, onkeypress, onkeydown, onkeyup, onmouseover, onsubmit, onload 등)는 모든 HTML 요소에서 공통적으로 사용할 수 있지만 특정 HTML 요소에만 한정적으로 사용 가능한 어트리뷰트도 있다.
요소 노드의 모든 어트리뷰트 노드는 요소 노드의 Element.prototype.attributes 프로퍼티로 취득할 수 있다.

인라인 스타일 조작 HTMLElement.prototype.style을 사용해 인라인 스타일(inline style)을 취득, 추가, 변경 가능하다. ex) background-color backgroundColor

클래스 조작(className) Element.prototype.className 프로퍼티는 HTML 요소의 class 어트리뷰트 값을 취득하거나 변경한다.

클래스 조작(classList) Element.prototype.classList 프로퍼티는 class 어트리뷰트의 정보를 담은 DOMTokenList 객체 반환한다.

  • add(…className) : 1개 이상의 문자열을 class 어트리뷰트 값으로 추가
  • remove(…className) : 1개 이상의 문자열과 일치하는 클래스를 class 어트리뷰트에서 삭제
  • item(index) : index에 해당하는 클래슬르 class 어트리뷰트에서 반환
  • contains(className) : 문자열과 일치하는 클래스가 class 어트리뷰트에 포함되어 있는지 확인
  • replace(oldClassName, newClassName) : class 어트리뷰트에서 첫 번째 문자열을 두 번째 문자열로 변경
  • toggle(className[,force]) : class 어트리뷰트에 문자열과 일치하는클래스가 존재하면 제거하고, 존재하지 않으면 추가

💡 이벤트

이벤트 타입

  • 마우스, 키보드 이벤트 (click, mouse move, keydown 등)
  • 포커스 이벤트 (focus, blur 등)
  • 폼 이벤트 (submit, reset)
  • 값 변경 이벤트 (change 등)
  • DOM 뮤테이션 이벤트 (DOMContentLoaded)
  • 뷰 이벤트 (resize, scroll)
  • 리소스 이벤트 (load, error 등)

이벤트 핸들러 등록

  1. 이벤트 핸들러 어트리뷰트 방식
<body>
    <bitton onclick="sayHi('park')"></button>
  
  	<script>
      function sayHi(name) {
        console.log(`Hi! ${name}`);
      }
    </script>
</body>
  1. 이벤트 핸들러 프로퍼티 방식
<body>
    <bitton>Click me!</button>
  
  	<script>
      const $btn = document.querySelector('button');
      
      // 이벤트 핸들러 프로퍼니에 이벤트 핸들러를 바인딩
      $btn.onclick = function () {
        console.log('button click');
      }
    </script>
</body>
  1. addEventListener 메서드 방식 : EventTarget.prototype.addEventListener 메서드를 사용해 이벤트 핸들러를 등록할 수 있다. addEventListener 메서드는 하나 이상의 이벤트 핸들러를 등록할 수 있다. (호출은 등록된 순서대로 진행)
  • 첫 번째 매개변수 : 이벤트 타입
  • 두 번째 매개변수 : 이벤트 핸들러
  • 세 번째 매개변수 : capture 사용 여부 (보통 생략함)

이벤트 핸들러 제거
EventTarget.prototype.removeEventListener 메서드를 사용해 addEventListener 메서드로 등록한 이벤트 핸들러를 제거한다. 단, addEventListener 메서드에 전달한 인수와 removeEventListener 메서드에 전달한 인수가 동일하지 않으면 이벤트 핸들러가 제거되지 않는다.

공통 프로퍼티

  • type : 이벤트 타입
  • target : 이벤트를 발생시킨 DOM 요소
  • currentTarget : 이벤트 핸들러가 바인딩된 DOM 요소
  • eventPhase : 이벤트 전파 단계 (0:없음, 1:캡처링, 2:타깃, 3: 버블링)
  • bubbles : 이벤트를 버블링 전파하는지 여부

이벤트 전파 는 이벤트 객체가 전파되는 방향에 따라 3단계로 구분할 수 있다.

  • 캡처링 단계(capturing phase) : 이벤트가 상위 요소에서 하위 요소 방향으로 전파
  • 타깃 단계(target phase) : 이벤트가 이벤트 타깃에 도달
  • 버블링 단계(bubbling phase) : 이벤트가 하위 요소에서 상위 요소 방향으로 전파
<html>
  <body>
    <ul id="fruits">
      <li id="apple">Apple</li>
      <li id="banana">Banana</li>
      <li id="orange">Orange</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById("fruits");

    $fruits.addEventListener("click", (e) => {
      console.log(`이벤트 단계 : ${e.eventPhase}`);
      console.log(`이벤트 타깃 : ${e.target}`);
      console.log(`현재 타깃 : ${e.currentTarget}`);
    });
  </script>
</html>

이벤트는 캡처링과 버블링을 통해 전파되지만, 버블링을 통해 전파되지 않은 이벤트들도 있다. 해당 이벤트들은 버블링이 발생하지 않기 때문에 이벤트 타깃의 상위 요소에서 캐치하려면 캡처링 단계의 이벤트를 캐치해야한다.

  • 포커스 이벤트 : focus/blur
  • 리소스 이벤트 : load/unload/abort/error
  • 마우스 이벤트 : mouseenter/mouseleave

이벤트 위임 은 여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 대신 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법을 말한다. 이벤트 위임을 통해 상위 DOM 요소에 이벤트 핸들러를 등록하면 여러 개의 하위 DOM 요소에 이벤트 핸들러를 등록할 필요가 없다. 또한 동적으로 하위 DOM 요소를 추가하더라도 일일이 추가된 DOM 요소에 이벤트 핸들러를 등록할 필요가 없다.

0개의 댓글