개발 관련 도서

모던 자바스크립트 - 이벤트(2)

mrban 2024. 7. 31. 22:36

40.8 DOM 요소의 기본 동작 조작

40.8.1 DOM 요소의 기본 동작 중단

  • DOM 요소는 저마다 기본 동작이 있다.
    • ex. a 요소를 클릭하면 href 어트리뷰트에 지정된 링크로 이동
  • 이벤트 객체의 preventDefault 메서드는 이러한 DOM 요소의 기본 동작을 중단시킨다.

40.8.2 이벤트 전파 방지

  • 이벤트 객체의 stopPropagation 메서드는 이벤트 전파를 중지시킨다. 즉, 상위 DOM 요소에게 이벤트가 전파되는 것을 막는 다는 것이다.

40.9 이벤트 핸들러 내부의 this

40.9.1 이벤트 핸들러 어트리뷰트 방식

  • 다음 예제의 handleClick 함수 내부의 this는 전역 객체 window를 가리킨다.
    • 일반 함수로서 호출되는 함수 내부의 this는 전역 객체를 가리키기 때문
  • 단, 이벤트 핸들러를 호출할 때 인수로 전달한 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.

40.9.2 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식

 

<!DOCTYPE html>
<html>
<head>
<body>
  <button class="btn1">0</button>
  <button class="btn2">0</button>
  <script>
  	const $btn1 = document.querySelector('.btn1');
    const $btn2 = document.querySelector('.btn2');
    
    // 이벤트 핸들러 프로퍼티 방식
    $btn1.onclick = function(e) {
    	console.log(this); // $btn1
      console.log(e.currentTarget); // $btn1
      console.log(this === e.currentTarget); // true
      
      ++this.textContent;
    }
    
    // 이벤트 리스너 메서드 방식
    $btn2.addEventListener('click', function(e) {
    	console.log(this); // $btn2
      console.log(e.currentTarget); // $btn2
      console.log(this === e.currentTarget); // true
      
      ++this.textContent;
    });
  </script>
</body>
</html>
  • 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식 모두 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.
    • 즉, 이벤트 핸들러 내부의 this는 이벤트 객체의 currentTarget 프로퍼티와 같다.
  • 화살표 함수로 정의한 이벤트 핸들러 내부의 this는 상위 스코프의 this를 가리킨다.
    • 화살표 함수는 함수 자체의 this 바인딩을 갖지 않는다.

40.10 이벤트 핸들러에 인수 전달

  • 이벤트 핸들러 어트리뷰트 방식은 함수 호출문을 사용할 수 있기 때문에 인수를 전달할 수 있다.
  • 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식의 경우 이벤트 핸들러를 브라우저가 호출하기 때문에 함수 호출문이 아닌 함수 자체를 등록하기 때문에 인수를 전달할 수 없다.
    • 그러나 이벤트 핸들러 내부에서 함수를 호출하면서 인수를 전달할 수 있다.
  • <!DOCTYPE html>
    <html>
    <head>
    <body>
      <lable>User Name <input type="text"/></lable>
      <em class="message"></em>
      <script>
      	const MIN_USER_NAME_LENGTH = 5;
        const $input = document.querySelector('input[type=text]');
        const $msg = document.querySelector('.message');
        
        const checkUserNameLength = min => {
        	$msg.textContent = $input.value.length < min ? `이름은 ${min}자 이상으로 입력해 주세요` : '';
        }
        
        // 이벤트 핸들러 내부에서 함수를 호출하면서 인수를 전달한다.
        $input.onblur = () => {
        	checkUserNameLength(MIN_USER_NAME_LENGTH);
        }
      </script>
    </body>
    </html>

40.11 커스텀 이벤트

40.11.1 커스텀 이벤트 생성

  • 개발자의 의도로 생성된 이벤트를 커스텀 이벤트라 한다.
    • 이벤트 생성자 함수는 첫 번째 인수로 이벤트 타입을 나타내는 문자열을 전달받는다.
    • 이때 이벤트 타입을 나타내는 문자열은 기존 이벤트 타입을 사용할 수도 있고, 임의의 문자열을 사용하여 새로운 이벤트 타입을 지정할 수도 있다.
    • 이 경우 일반적으로 CustomEvent 이벤트 생성자 함수를 사용한다.
// KeyboardEvent 생성자 함수로 keyup 이벤트 타입의 커스텀 이벤트 객체를 생성
const keyboardEvent = new KeyboardEvent('keyup');
console.log(keyboardEvent.type); // keyup

// CustomEvent 생성자 함수로 foo 이벤트 타입의 커스텀 이벤트 객체를 생성
const customEvent = new CustomEvent('foo');
console.log(customEvent.type); // foo

40.11.2 커스텀 이벤트 디스패치

 

<!DOCTYPE html>
<html lang="kr">
  <head>
    <meta charset="UTF-8" />
    <title>Practice</title>
  </head>
  <body>
    <button class="btn">Click me</button>
    <script>
      const $button = document.querySelector('.btn');

      $button.addEventListener('click', e => {
        console.log(e) // MouseEvent {...}
        alert(`${e} clicked!`);
      });

      // 커스텀 이벤트 생성
      const customEvent = new MouseEvent('click');

      // 커스텀 이벤트 디스패치(동기 처리). click 이벤트가 발생한다.
      $button.dispatchEvent(customEvent);
    </script>
  </body>
</html>
  • 생성된 커스텀 이벤트는 dispatchEvent 메서드로 디스패치(이벤트를 발생시키는 행위)할 수 있다.
  • dispatchEvent 메서드에 이벤트 객체를 인수로 전달하면서 호출하면 인수로 전달한 이벤트 타입의 이벤트가 발생한다.
  • 기존 타입이 아닌 임의의 이벤트 타입을 지정하여 커스텀 이벤트 객체를 생성한 경우 반드시addEventListener 메서드 방식으로 이벤트 핸들러를 등록해야 한다.
  • 이벤트 핸들러 어트리뷰트/프로퍼티 방식으로 등록할 수 없는 이유는 on + 이벤트 타입으로 이루어진 이벤트 핸들러 어트리뷰트/프로퍼티가 요소 노드에 존재하지 않기 때문이다.
    • ex. 'foo' 라는 임의의 이벤트 타입으로 커스텀 이벤트를 생성할 경우 'onfoo'라는 핸들러 어트리뷰트/프로퍼티가 요소 노드에 존재하지 않는다.