40장 이벤트

Boseong Choi·2023년 7월 27일
0

40.1 이벤트 드리븐 프로그래밍

브라우저는 처리해야 할 특정 사건이 발생하면 이를 감지하여 이벤트를 발생시킨다. 이때 이벤트가 발생했을 때 호출될 함수를 이벤트 핸들러라 하고, 이벤트가 발생했을 때 브라우저에게 이벤트 핸들러 호출을 위임하는 것을 이벤트 핸들러 등록이라 한다.

브라우저는 사용자의 버튼 클릭을 감지하여 클릭 이벤트를 발생시킬 수 있다. 그리고 클릭 이벤트가 발생하면 특정함수를 호출하도록 브라우저에게 위임할 수 있다. 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식을 이벤트 드리븐 프로그래밍이라 한다.

40.2 이벤트 타입

  1. 마우스 이벤트
  2. 키보드 이벤트
  3. 포커스 이벤트
  4. 폼 이벤트
    기타 등등

40.3 이벤트 핸들러 등록

이벤트 핸들러는 이벤트가 발생했을 때 브라우저에 호출을 위임한 함수. 이벤트가 발생하면 브라우저에 의해 호출될 함수가 이벤트 핸들러다.

  1. 어트리뷰트 방식
    HTML 요소의 어트리뷰트에는 이벤트 핸들러 어트뷰리트가 있다. 가급적 사용하지 말자.

  2. 프로퍼티 방식
    이벤트 핸들러 프로퍼티에 함수를 바인딩하면 이벤트 핸들러가 등록된다.

const $button = document.querySelector('button');

// 이벤트 핸들러 프로퍼티에 이벤트 핸들러를 바인딩한다.
$button.onclick = function () {
  // $button -> 이벤트 타깃, onclick -> 이벤트 타입, function () {} -> 이벤트 핸들러
  console.log('button clicked');
};

단, 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다는 단점이 있다.

  1. addEventListener 메서드
    이벤트 타깃.addEventListener(이벤트 타입, 이벤트 핸들러[, 옵션]);
    addEventListener 메서드는 이벤트 핸들러 프로퍼티에 바인딩된 이벤트 핸들러에 영향을 주지 않는다. 따라서 버튼 요소에서 클릭이벤트가 발생하면 2개의 이벤트 모두 호출된다. 단, 참조가 동일한 이벤트 핸들러를 중복 등록할 수 없다.

40.4 이벤트 핸들러 제거

addEventListener 메서드로 등록한 이벤트 핸들러는 removeEventListener 메서드로 제거할 수 있다. 인수는 addEventListener 메서드와 동일하게 전달한다. 하지만, 인수가 일치하지 않으면 제거되지 않는다.

removeEventListener 메서드에 인수로 전달한 이벤트 핸들러는 addEventListener 메서드로 등록한 이벤트 핸들러와 동일한 함수 객체여야 한다. 따라서 무명 함수를 사용한 이벤트 핸들러는 제거할 수 없다.

무명함수에 대해 직접 접근하기 어렵기 때문. 제거하려면 addEventListener 메서드에 전달한 이벤트 핸들러를 변수에 할당하여 사용해야 한다.

$button.addEventListener('click', () => {
  console.log('button clicked');
});

$button.removeEventListener('click', () => {
  console.log('button clicked');
}); // 제거되지 않는다.

이벤트 핸들러 프로퍼티 방식으로 등록한 이벤트 핸들러는 removeEventListener 메서드로 제거할 수 없다. 이벤트 핸들러 프로퍼티 방식으로 등록한 이벤트 핸들러는 null을 할당하여 제거한다.

40.5 이벤트 객체

생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달된다.

function showCoords(event) {
  $msg.textContent = `X: ${event.clientX}, Y: ${event.clientY}`;
}

document.onclick = showCoords;

이벤트 객체 : PointerEvent {isTrusted: true, pointerId: 0, width: 1, height: 1, pressure: 0, …}
클릭 이벤트 = document.onclick = showCoords; -> 클릭 이벤트가 발생하면 showCoords 함수가 호출된다.

이때 이벤트 객체가 showCoords 함수의 첫 번째 인수로 전달되고 파라미터 event에 할당된다.
함수 이름만을 쓰는 이유는 이벤트의 결과값을 내가 아직 모르기 때문에 브라우저에게 위임하는 것이다. 그래서 암묵적으로 함수 이름을 쓰는 것이다라고 이해했다.

40.6 이벤트 전파

DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파된다. 그림 40-8 보시면 이해가 더 쉬울듯. 상위 요소에서 하위 요소로 전파되는 것이 캡처링 단계. 이벤트가 타깃에 도달하는게 타깃 단계. 하위 요소에서 상위 요소로 전파되는 것이 버블링 단계.

이처럼 이벤트는 이벤트를 발생시킨 타깃은 물론 상위 DOM 요소에서도 캐치할 수 있다.

40.7 이벤트 위임

하위 요소에 이벤트를 걸지 않고 이벤트 전파의 특징을 활용해서 상위 요소에 이벤트를 걸어서 상위 요소 너한테 맡길게.

784P 맨 아래 코드는 하위 요소에 일일이 이벤트 핸들러를 등록하고 있음. 만약 하위 요소가 동적이거나 한 100개 되면은 매우 불편. 이를 보완한게 786P 상위 요소에 이벤트 핸들러 등록.

matches 메서드. ul → li 로 전파되는건 눈에 잘 보이는 편인데. 이게 컴포넌트 방식으로 만들거나, 구조가 복잡할경우 잘 파악이 안됨. 이럴 때 특정 노드를 탐색해서 전파가 가능한지 사용하기도 하고, 허용되지 않은 타깃이 전파되는걸 막기도 함. 예제 40-33 타깃이 #fruits 자식 요소가 아니면 얼리 리턴해줌.

40.8 DOM 요소의 기본 동작 조작

  1. preventDefault
    기본 동작을 중지시킨다. 회원 가입 폼이 있는데, 따로 조건 제한 안하면 공백을 입력하든 입력 안하든 form action은 하게 되어있음. 그걸 방지하기 위해 input의 값을 받아서 그게 null 또는 공백이면 e.preventDefault() 해서 제출 동작을 막을 수 있음.

  2. stopPropagation
    전파를 막는 메서드. 캡처링/버블링 둘다.

40.9 이벤트 핸들러 내부의 this

일반함수로서 호출되는 함수 내부의 this는 전역 객채를 가리킴. 근데 예외로 이벤트 핸들러 어트리뷰트 방식에서 이벤트 핸들러를 호출할 때 아규먼트를 this로 넣으면 이벤트를 바인딩한 DOM 요소를 가리킨다.

그리고 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식은 내부의 this가 이벤트를 바인딩한 DOM 요소를 가리킨다. 근데 이벤트핸들러를 화살표 함수로 정의하면 상위 스코프의 this를 가리킴. 화살표 함수는 자체적으로 this 바인딩이 없기 때문에.

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

원래 함수에 아규먼트를 전달하려면 호출할 때 전달해야 하는데 이벤트 핸들러 프로퍼티랑 addEventListener 메서드는 이벤트 핸들러를 브라우저가 호출함. 그래서 아규먼트를 전달할 수 없지만 방법이 하나 있음.

40.11 커스텀 이벤트

이벤트 객체는 MoustEvent 같은 이벤트 생성자 함수로 생성할 수 있다.
예제 40-49 MouseEvent 생성자 함수로 클릭 이벤트 타입의 이벤트 객체를 생성.

797p 커스텀 이벤트 디스패치 : 실제로 이벤트가 발생한 것처럼 하고 싶다. 실제로 클릭한게 아니라 커스텀 이벤트 만들어놓고 클릭이벤트가 발생한 것처럼 구현할 때.

profile
Frontend Developer

0개의 댓글