쑤쑤_CS 기록장

33. 이벤트 본문

IT 지식 기록/JavaScript 정리

33. 이벤트

(╹◡╹)_ 2020. 12. 28. 16:45
728x90

#1. 이벤트(Event)

이벤트

: 어떤 사건

  • 브라우저에서의 이벤트

    사용자가 버튼을 클릭했을때, 웹페이지가 로드되었을 때 (DOM 요소)

  • 이벤트가 발생하는 시점이나 순서를 사전에 인지할 수 없다

    이벤트가 발생하면 누군가 이를 감지할 수 있어야 하며 대응하는 처리를 호출해 주어야 한다

  • 브라우저는 이벤트를 감지할 수 있으며 이벤트 발생 시에는 통지해준다.

    이 과정을 통해 사용자와 웹페이지는 상호작용(Interaction)이 가능

 

이벤트 핸들러

: 이벤트에 대응하는 처리를 기술

  • 이벤트가 발생하면 그에 맞는 반응을 해야 한다.

  • 이벤트는 일반적으로 함수에 연결되며, 함수는 이벤트가 발생되면 실행된다

 

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

  • 브라우저 : 단일 쓰레드(single-thread) > 이벤트 드리븐(event-driven)방식으로 동작

  • 단일 쓰레드 (single-thread)
    : 쓰레드가 하나 뿐이다. 하나의 작업(task)만을 처리할 수 있다.

  •  

    하지만 웹 어플리케이션은 동시에 여러개의 task를 처리하는 것처럼 느껴진다.

  • 자바스크립트의 동시성(Concurrency)를 지원 : 이벤트 루프(Event Loop)

<이벤트 루프와 브라우저의 환경>

 

자바스크립트 엔진 (2)

  • Call Stack(호출 스택)

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

    : 동적으로 생성된 객체 인스턴스가 할당되는 영역이다.

 

동시성 (Concurrency) 지원

동시성을 지원하기 위해 필요한 비동기 요청 처리는 자바스크립트 엔진을 구동하는 환경 즉 브라우저(또는 Node.js)가 담담한다.

  • Event Queue(Task Queue)

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

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

 

#3. 이벤트의 종류

#3.1 UI Event

#3.2 Keyboard Event

#3.3 Mouse Event

#3.4 Focus Event

#3.5 Form Event

#3.6

Clipboard Event

#4. 이벤트 핸들러 등록

이벤트 핸들러를 이벤트에 등록하는 방법(3)

 

#4.1 인라인 이벤트 핸들러 방식

HTML 요소의 이벤트 핸들러 어트리뷰트에 이벤트 핸들러를 등록하는 방법

<!DOCTYPE html>
<html>
<body>
  <button onclick="myHandler()">Click me</button>
  <script>
    function myHandler() {
      alert('Button clicked!');
    }
  </script>
</body>
</html>

#4.2 이벤트 핸들러 프로퍼티 방식

: 인라인 이벤트 핸들러 방식처럼 HTML과 Javascript가 뒤섞이는 문제는 해결할 수 있는 방식이다.
하지만 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만을 바인딩할 수 있다는 단점이 있다.

<!DOCTYPE html>
<html>
<body>
  <button class="btn">Click me</button>
  <script>
    const btn = document.querySelector('.btn');

    // 이벤트 핸들러 프로퍼티 방식은 이벤트에 하나의 이벤트 핸들러만을 바인딩할 수 있다
    // 첫번째 바인딩된 이벤트 핸들러 => 실행되지 않는다.
    btn.onclick = function () {
      alert('① Button clicked 1');
    };

    // 두번째 바인딩된 이벤트 핸들러
    btn.onclick = function () {
      alert('① Button clicked 2');
    };

    // addEventListener 메소드 방식
    // 첫번째 바인딩된 이벤트 핸들러
    btn.addEventListener('click', function () {
      alert('② Button clicked 1');
    });

    // 두번째 바인딩된 이벤트 핸들러
    btn.addEventListener('click', function () {
      alert('② Button clicked 2');
    });
  </script>
</body>
</html>

 

#4.3 addEventListener 메소드 방식

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

 

addEventListener 함수 방식의 이전 방식에 비해 나은 장점

  • 하나의 이벤트에 대해 하나 이상의 이벤트 핸들러를 추가할 수 있다.
  • 캡처링과 버블링을 지원한다.
  • HTML 요소뿐만아니라 모든 DOM 요소(HTML, XML, SVG)에 대해 동작한다. 브라우저는 웹 문서(HTML, XML, SVG)를 로드한 후, 파싱하여 DOM을 생성한다.
<!DOCTYPE html>
<html>
<body>
  <script>
    addEventListener('click', function () {
      alert('Clicked!');
    });
  </script>
</body>
</html>

 

 

#5. 이벤트 핸들러 함수 내부의 this

#5.1 인라인 이벤트 핸들러 방식

이벤트 핸들러는 일반 함수로서 호출되므로 이벤트 핸들러 내부의 this는 전역 객체 window를 가리킨다.

  <script>
    function foo () {
      console.log(this); // window
    }
  </script>

#5.2 이벤트 핸들러 프로퍼티 방식

이벤트 핸들러는 메소드이므로 이벤트 핸들러 내부의 this는 이벤트에 바인딩된 요소를 가리킨다.
이것은 이벤트 객체의 currentTarget 프로퍼티와 같다.

  <script>
    const btn = document.querySelector('.btn');

    btn.onclick = function (e) {
      console.log(this); // <button id="btn">Button</button>
      console.log(e.currentTarget); // <button id="btn">Button</button>
      console.log(this === e.currentTarget); // true
    };
  </script>

#5.3 addEventListener 메소드 방식

이벤트 핸들러 내부의 this는 이벤트 리스너에 바인딩된 요소(currentTarget)를 가리킨다.
이것은 이벤트 객체의 currentTarget 프로퍼티와 같다.

 <script>
    const btn = document.querySelector('.btn');

    btn.addEventListener('click', function (e) {
      console.log(this); // <button id="btn">Button</button>
      console.log(e.currentTarget); // <button id="btn">Button</button>
      console.log(this === e.currentTarget); // true
    });
  </script>
  

#6. 이벤트의 흐름

  • 계층적 구조에 포함되어 있는 HTML 요소에 이벤트가 발생할 경우 연쇄적 반응
  • 이벤트가 전파되는데, 전파 방향에 따라 버블링과 캡처링으로 구분

버블링

: 자식 요소에서 발생한 이벤트가 부모 요소로 전파되는 것

 

캡처링

: 자식 요소에서 발생한 이벤트가 부모 요소부터 시작하여 이벤트를 발생시킨 자식 요소까지 도달하는 것

 

버블링과 캡처링은 둘 중 하나 선택이 아니라 캡처링부터 시작하여 버블링으로 종료하는 것이다.

이벤트가 발생했을 때 캡처링과 버블링은 순차적으로 발생한다.

 

addEventListener 메소드의 세번째 매개변수에
- true를 설정하면 캡처링으로 전파되는 이벤트를 캐치하고

- false 또는 미설정하면 버블링으로 전파되는 이벤트를 캐치한다.

 

#7. Event 객체

: 이벤트를 발생시킨 요소와 발생한 이벤트에 대한 유용한 정보를 제공한다.

 

이벤트가 발생하면 event 객체는 동적으로 생성되며 이벤트를 처리할 수 있는 이벤트 핸들러에 인자로 전달된다.

<!DOCTYPE html>
<html>
<body>
  <em class="message"></em>
  <script>
  function showCoords(e, msg) {
    msg.innerHTML =
      'clientX value: ' + e.clientX + '<br>' +
      'clientY value: ' + e.clientY;
  }

  const msg = document.querySelector('.message');

  addEventListener('click', function (e) {
    showCoords(e, msg);
  });
  </script>
</body>
</html>
  • event 객체는 이벤트 핸들러에 암묵적으로 전달된다.
  • 이벤트 핸들러를 선언할 때, event 객체를 전달받을 첫번째 매개변수를 명시적으로 선언해야 한다.
  • 예제에서 e라는 이름으로 매개변수를 지정했으나 다른 이름을 사용해도 상관 없다.

#7.1 Event Property

  • Event.target
    : 실제로 이벤트를 발생시킨 요소를 가리킨다.

  • Event.currentTarget
    : 이벤트에 바인딩된 DOM요소를 가리킨다. 즉 addEventLinstener 앞에 기술된 객체를 가리킨다.

  • Event.type
    : 발생한 이벤트의 종류를 나타내는 문자열을 반환한다.

  • Event.cancelable
    : 요소의 기본 동작을 취소시킬 수 있는지 여부(true/false)를 나타낸다.

  • Event.eventPhase
    : 이벤트의 흐름flow 상에서 어느 단계에 있는지를 반환한다.

 

#8. Event Delegation (이벤트 위임)

이벤트 위임(Event Delegation)

: 다수의 자식 요소에 각각 이벤트 핸들러를 바인딩하는 대신 하나의 부모 요소에 이벤트 핸들러를 바인딩하는 방법

이는 이벤트가 이벤트 흐름에 의해 이벤트를 발생시킨 요소의 부모 요소에도 영향(버블링)을 미치기 때문에 가능한 것이다.

 

예를 들어 6개의 자식 요소에 각각 이벤트 핸들러를 바인딩하는 것 대신 부모 요소(ul#post-list)에 이벤트 핸들러를 바인딩하는 것이다.

 

실제로 이벤트를 발생시킨 요소를 알아내기 위해서는 Event.target을 사용한다.

 

#9. 기본 동작의 변경

이벤트 객체는 요소의 기본 동작과 요소의 부모 요소들이 이벤트에 대응하는 방법을 변경하기 위한 메소드는 가지고 있다.

#9.1 Event.preventDefault()

폼을 submit하거나 링크를 클릭하면 다른 페이지로 이동하게 된다. 

요소가 가지고 있는 동작을 중단시키기 위한 메소드 preventDefault()

#9.2 Event.stopPropagation()

어느 한 요소를 이용하여 이벤트를 처리한 후 이벤트가 부모 요소로 전파되는 것을 중단시키기 위한 메소드.

부모 요소에 동일한 이벤트에 대한 다른 핸들러가 지정되어 있을 경우 사용된다.

#9.3 preventDefault & stopPropagation

기본 동작의 중단과 버블링, 캡처링의 중단을 동시에 실시하는 방법

이 방법은 jQuery를 사용할 때와 아래와 같이 사용할 때만 적용된다.

<!DOCTYPE html>
<html>
<body>
  <div>
    <a href="http://www.google.com">go</a>
  </div>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
  <script>

  // within jQuery
  $('a').click(function (e) {
    e.preventDefault(); // OK
  });

  $('a').click(function () {
    return false; // OK --> e.preventDefault() & e.stopPropagation().
  });

  // pure js
  document.querySelector('a').addEventListener('click', function(e) {
    // e.preventDefault(); // OK
    return false;       // NG!!!!!
  });
  </script>
</body>
</html>
728x90
Comments