Skip to content

Latest commit

 

History

History
286 lines (220 loc) · 12.8 KB

이벤트.md

File metadata and controls

286 lines (220 loc) · 12.8 KB

이벤트

  • 이벤트(event)는 어떤 사건을 의미한다. 브라우저에서의 이벤트란 예를 들어 사용자가 버튼을 클릭했을 때, 웹페이지가 로드되었을 때와 같은 것인데 이것은 DOM 요소와 관련이 있다.
  • 브라우저는 이벤트를 감지할 수 있으며 이벤트 발생 시에는 통지해 준다. 이 과정을 통해 사용자와 웹페이지는 상호작용(Interaction)이 가능하게 된다.
<script>
document.querySelector('.myButton').addEventListener('click', function () {
  alert('Clicked!');
});
</script>
  • myButton이라는 클래스명인 태그에 버튼을 누르면 함수의 콜백함수가 실행된다. alert('Clicked!'); 발생

image

이벤트 루프(Event Loop)와 동시성(Concurrency)

  • 브라우저는 단일 쓰레드(single-thread)에서 이벤트 드리븐(event-driven) 방식으로 동작한다.
  • 단일 쓰레드는 쓰레드가 하나뿐이라는 의미이며, 하나의 작업(task)만을 처리할 수 있다는 것을 의미한다. 하지만 실제로 동작하는 웹 애플리케이션은 많은 task가 동시에 처리되는 것처럼 느껴진다. 이처럼 자바스크립트의 동시성(Concurrency)을 지원하는 것이 바로 **이벤트 루프(Event Loop)**이다.

image

  • 브라우저의 환경을 그림으로 표현

대부분의 자바스크립트 엔진은 크게 2개의 영역으로 나뉜다.

Call Stack(호출 스택)

  • 작업이 요청되면(함수가 호출되면) 요청된 작업은 순차적으로 Call Stack에 쌓이게 되고 순차적으로 실행된다. 자바스크립트는 단 하나의 Call Stack을 사용하기 때문에 해당 task가 종료하기 전까지는 다른 어떤 task도 수행될 수 없다.

Heap

  • 동적으로 생성된 객체 인스턴스가 할당되는 영역이다.
  • 자바스크립트 엔진은 단순히 작업이 요청되면 Call Stack을 사용하여 요청된 작업을 순차적으로 실행한다.
  • 동시성(Concurrency)을 지원하기 위해 필요한 비동기 요청(이벤트를 포함) 처리는 자바스크립트 엔진을 구동하는 환경 즉 브라우저(또는 Node.js)가 담당한다.

Event Queue(Task Queue)

  • 비동기 처리 함수의 콜백 함수, 비동기식 이벤트 핸들러, Timer 함수(setTimeout(), setInterval())의 콜백 함수가 보관되는 영역으로 이벤트 루프(Event Loop)에 의해 특정 시점(Call Stack이 비어졌을 때)에 순차적으로 Call Stack으로 이동되어 실행된다.

Event Loop(이벤트 루프)

  • Call Stack 내에서 현재 실행중인 task가 있는지 그리고 Event Queue에 task가 있는지 반복하여 확인한다. 만약 Call Stack이 비어있다면 Event Queue 내의 task가 Call Stack으로 이동하고 실행된다.

UI Event

Event Description
load 웹페이지의 로드가 완료되었을 때
unload 웹페이지가 언로드될 때(주로 새로운 페이지를 요청한 경우)
error 브라우저가 자바스크립트 오류를 만났거나 요청한 자원이 존재하지 않는 경우
resize 브라우저 창의 크기를 조절했을 때
scroll 사용자가 페이지를 위아래로 스크롤할 때
select 텍스트를 선택했을 때

Keyboard Event

Event Description
keydown 키를 누르고 있을 때
keyup 누르고 있던 키를 뗄 때
keypress 키를 누르고 뗏을 때

Mouse Event

Event Description
click 마우스 버튼을 클릭했을 때
dbclick 마우스 버튼을 더블 클릭했을 때
mousedown 마우스 버튼을 누르고 있을 때
mouseup 누르고 있던 마우스 버튼을 뗄 때
mousemove 마우스를 움직일 때 (터치스크린에서 동작하지 않는다)
mouseover 마우스를 요소 위로 움직였을 때 (터치스크린에서 동작하지 않는다)
mouseout 마우스를 요소 밖으로 움직였을 때 (터치스크린에서 동작하지 않는다)

Focus Event

Event Description
focus/focusin 요소가 포커스를 얻었을 때
blur/foucusout 요소가 포커스를 잃었을 때

Form Event

Event Description
input input 또는 textarea 요소의 값이 변경되었을 때
contenteditable 어트리뷰트를 가진 요소의 값이 변경되었을 때
change select box, checkbox, radio button의 상태가 변경되었을 때
submit form을 submit할 때 (버튼 또는 키)
reset reset 버튼을 클릭할 때 (최근에는 사용 안함)

Clipboard Event

Event Description
cut 콘텐츠를 잘라내기할 때
copy 콘텐츠를 복사할 때
paste 콘텐츠를 붙여넣기할 때

이벤트 핸들러 등록 방법

inline 방식

  • 인라인 방식은 이벤트를 이벤트 대상의 태그 속성으로 지정하는 것이다.
<input type="button" onclick="alert('Hello world');" value="button" />
<button onclick="myHandler1(); myHandler2();">Click me</button>

<script>
    function myHandler1() {
      alert('myHandler1');
    }
    function myHandler2() {
      alert('myHandler2');
    }
</script>

addEventListener 방식

  • addEventListener 메소드를 이용하여 대상 DOM 요소에 이벤트를 바인딩하고 해당 이벤트가 발생했을 때 실행될 콜백 함수(이벤트 핸들러)를 지정한다.

image

addEventListener 함수 방식은 이전 방식에 비해 아래와 같이 보다 나은 장점을 갖는다.

  • 하나의 이벤트에 대해 하나 이상의 이벤트 핸들러를 추가할 수 있다.
  • 캡처링과 버블링을 지원한다.
  • HTML 요소뿐만아니라 모든 DOM 요소(HTML, XML, SVG)에 대해 동작한다. 브라우저는 웹 문서(HTML, XML, SVG)를 로드한 후, 파싱하여 DOM을 생성한다.
<input type="button" id="target" value="button" />

<script>
    var t = document.getElementById('target');
    t.addEventListener('click', function(event){
        alert('Hello world, '+event.target.value);
    });
</script>

Event 객체

  • event 객체는 이벤트를 발생시킨 요소와 발생한 이벤트에 대한 유용한 정보를 제공한다.
  • 이벤트가 발생하면 event 객체는 동적으로 생성되며 이벤트를 처리할 수 있는 이벤트 핸들러에 인자로 전달된다.
<!DOCTYPE html>
<html>
<body>
  <p>클릭하세요. 클릭한 곳의 좌표가 표시됩니다.</p>
  <em class="message"></em>

  <script>
  function showCoords(e) { // e: event object
    const msg = document.querySelector('.message');
    msg.innerHTML =
      'clientX value: ' + e.clientX + '<br>' +
      'clientY value: ' + e.clientY;
  }
  addEventListener('click', showCoords); // 참조하는게 없으면 기본 window 전역 객체
  </script>
</body>
</html>

image

  • event 객체는 이벤트 핸들러에 암묵적으로 전달된다. 그러나 이벤트 핸들러를 선언할 때, event 객체를 전달받을 첫번째 매개변수를 명시적으로 선언하여야 한다.

Event 객체 속성 종류

  • Event.target: 실제로 이벤트를 발생시킨 요소를 가리킨다.
  • Event.currentTarget: 코드에서 이벤트에 바인딩된 DOM 요소를 가리킨다. 즉, addEventListener 앞에 기술된 객체를 가리킨다.
<div>
  <button>배경색 변경</button>
</div>
document.querySelector("div").addEventListener("click", function () {
  // this: 이벤트에 바인딩된 DOM 요소(div 요소)
  console.log("this: ", this);

  // target: 실제로 이벤트를 발생시킨 요소(button 요소 또는 div 요소)
  console.log("e.target:", e.target);

  // currentTarget: 이벤트에 바인딩된 DOM 요소(div 요소)
  console.log("e.currentTarget: ", e.currentTarget);
});
  • div를 이벤트리스너로 등록했다. 그런데 div안에 button이 있는데, div영역을 click하든 button영역을 click하든 똑같이 이벤트가 발생하게된다.
    • this : dive
    • target : buttone
    • currentTarget : div
  • Event.type: 발생한 이벤트의 종류를 나타내는 문자열을 반환한다.
  • Event.cancelable: 요소의 기본 동작을 취소시킬 수 있는지 여부(true/false)를 나타낸다.
  • Event.eventPhase: 이벤트 흐름(event flow) 상에서 어느 단계(event phase)에 있는지를 반환한다.
    • 이벤트 흐름(event flow) 상에서 어느 단계(event phase)에 있는지를 반환한다.
      반환값 의미
      0 이벤트 없음
      1 캡쳐링 단계
      2 타깃
      3 버블링 단계
  • Event Delegation (이벤트 위임): 일반적으로 모든 li 요소가 클릭 이벤트에 반응하는 처리를 구현하고 싶은 경우, li 요소에 이벤트 핸들러를 바인딩하면 총6개의 이벤트 핸들러를 바인딩하여야 한다.
<ul id="post-list">
  <li id="post-1">Item 1</li>
  <li id="post-2">Item 2</li>
  <li id="post-3">Item 3</li>
  <li id="post-4">Item 4</li>
  <li id="post-5">Item 5</li>
  <li id="post-6">Item 6</li>
</ul>
function printId() {
  console.log(this.id);
}

document.querySelector("#post-1").addEventListener("click", printId);
document.querySelector("#post-2").addEventListener("click", printId);
document.querySelector("#post-3").addEventListener("click", printId);
document.querySelector("#post-4").addEventListener("click", printId);
document.querySelector("#post-5").addEventListener("click", printId);
document.querySelector("#post-6").addEventListener("click", printId);
  • 이러한 경우이벤트 위임(Event Delegation)을 사용한다.
  • 이벤트 위임은 다수의 자식 요소에 각각 이벤트 핸들러를 바인딩하는 대신 하나의 부모 요소에 이벤트 핸들러를 바인딩하는 방법이다.
  • 위의 경우 6개의 자식 요소에 각각 이벤트 핸들러를 바인딩하는 것 대신 부모 요소(ul#post-list)에 이벤트 핸들러를 바인딩하는 것이다.
  • 또한 DOM 트리에 새로운 li 요소를 추가하더라도 이벤트 처리는 부모 요소인 ul 요소에 위임되었기 때문에 새로운 요소에 이벤트를 핸들러를 다시 바인딩할 필요가 없다.
  • 이는 이벤트가 이벤트 흐름에 의해 이벤트를 발생시킨 요소의 부모 요소에도 영향(버블링)을 미치기 때문에 가능한 것이다. 실제로 이벤트를 발생시킨 요소를 알아내기 위해서는 Event.target을 사용한다.
<html>
<body>
  <ul class="post-list">
    <li id="post-1">Item 1</li>
    <li id="post-2">Item 2</li>
    <li id="post-3">Item 3</li>
    <li id="post-4">Item 4</li>
    <li id="post-5">Item 5</li>
    <li id="post-6">Item 6</li>
  </ul>
  <div class="msg">
  <script>
    const msg = document.querySelector('.msg');
    const list = document.querySelector('.post-list')

    list.addEventListener('click', function (e) {
      // 이벤트를 발생시킨 요소
      console.log('[target]: ' + e.target);
      // 이벤트를 발생시킨 요소의 nodeName
      console.log('[target.nodeName]: ' + e.target.nodeName);

      // li 요소 이외의 요소에서 발생한 이벤트는 대응하지 않는다.
      if (e.target && e.target.nodeName === 'LI') {
        msg.innerHTML = 'li#' + e.target.id + ' was clicked!';
      }
    });
  </script>
</body>
</html>

image


참고