[40장] 이벤트(2)

2022. 1. 30. 11:35책/자바스크립트 딥다이브

5. 이벤트 객체
이벤트가 발생하면 이벤트에 관련한 정보를 담고 있는 이벤트 객체가 동적으로 생성되고,
생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달된다
다시한번 말하지만 이벤트 '객체' (event Object)가 동적으로 생성된다는거임

function handleClick( event ) {
    // 맨날 보던 저 event 말하는거임ㅎㅎ
}

대신 이벤트 핸들러 어트리뷰트 방식으로 이벤트 달거면 주의사항이 있음

ㅇ이벤트 핸들러 어트리뷰트 방식
  - 파라미터 자리를 반드시 event란 이름으로 지정해야함
  - 이유라면 당연한건데 암묵적으로 만들어주는 프로퍼티 함수가 애초에 인수를 event로 정의해놨기 때문
  - 그걸 받아 쓰려면 당연히 event 이름 맞춰줘야겠쥬?

function onclick(event) {
      handleClick( e ) // 이런식으로 파라미터명이 다르면 못받아와~ 이러다 다 죽어~
}

<button onclick="handleClick(event)">저장하기</button>

5.1 이벤트 객체 상속 구조
이벤트 발생하면 이벤트 타입에 따라 이벤트 객체가 생성되며, 아래와 같은 상속 구조를 갖는다. 


위 그림 모두가 생성자 함수라 여지껏 e 라고 써왔던 이벤트 객체는 생성자 함수를 호출해 만들어온 것이다

 

e = new FocusEvent('focus');
e = new MouseEvent('click');
e = new KeyboardEvent('keyup');
e = new InputEvent('change');

 


이처럼 이벤트 객체는 암묵적으로 생성자 함수에 의해 생성된 것이며, 당연히 프로토타입 체인의 일원이 된다. 예를 들어 'click' 이벤트에서 생기는 MouseEvent 타입의 이벤트 객체는 아래와 같은 프로토타입 체인의 일원이 된다



ㅇEvent 인터페이스 / 기타 하위 인터페이스
  - Event 인터페이스는 DOM 내에서 발생한 이벤트에 의해 생성되는 이벤트 객체를 나타낸다. 
  - 모든 이벤트 객체의 공통 프로퍼티가 정의돼있음
  - 하위 인터페이스에는( FocusEvent, MouseEvent, KeyboardEvent 같은 ) 자기들 타입에 맞는 고유한 프로퍼티가 정의돼있음


5.2 이벤트 객체의 공통 프로퍼티
Event 인터페이스의 이벤트 관련 프로퍼티는 모든 이벤트 객체가 상속받는 공통 프로퍼티이다.

 

5.3 마우스 정보 취득
click, dbclick, mousedown/up/move/enter/leave 이벤트 발생시 MouseEvent 타입의 이벤트 객체가 생성됨
MouseEvent 타입의 이벤트 객체는 아래 고유 프로퍼티를 갖는다(당연히 더 있긴함)
  - 좌표정보 프로퍼티 : screenX/Y clientX/Y pageX/Y offsetX/Y
  - 버튼벙보 프로퍼티 : altKey, ctrlKey, shiftKey, button

아래는 드래그 이벤트 예시

<style>
        .box {
            width: 100px;
            height: 100px;
            background-color: #fff700;
            border: 5px solid orange;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="box"></div>
<script>
    const $box = document.querySelector('.box');
    const initalMousePos = { x: 0, y: 0 };
    const offset = { x: 0, y: 0 };

    const move = e => {
        offset.x = e.clientX - initalMousePos.x;
        offset.y = e.clientY - initalMousePos.y;

        console.log(offset)

        // translate3d는 GPU를 사용하므로 absolute의 top, left보다 빠름
        // 추가로 top, left는 레이아웃에 영향을 줌 
        $box.style.transform = `translate3d(${offset.x}px, ${offset.y}px, 0)`;
    };

    $box.addEventListener('mousedown', e => {
        initalMousePos.x = e.clientX - offset.x;
        initalMousePos.y = e.clientY - offset.y;
        document.addEventListener('mousemove', move);
    });

    document.addEventListener('mouseup', ()=>{
        document.removeEventListener('mousemove', move);
    });
</script>
</body>



5.4 키보드 정보 취득
keydown, keyup, keypress 이벤트 발생시 KeyboardEvent 타입의 이벤트 객체 생성.
이벤트 객체는 altKey, ctrlKey, metaKey, key같은 고유 프로퍼티를 가짐
아래는 인풋에 문자를 치고 엔터를 누르면 그대로 보여주는 예제

<body>
    <input type="text">
    <em class="message"></em>
<script>
    const $input = document.querySelector('input[type=text]');
    const $msg = document.querySelector('.message');
    
    $input.onkeyup = e => {
        if (e.key === 'Enter') {
            $msg.textContent = e.target.value;
            e.target.value = '';
        }
    }
</script>
</body>



  - KeyboardEvent 타입의 이벤트 객체는 입력한 키 값을 문자열로 반환하는 key 프로퍼티를 제공함. 
  - 그래서 엔터를 누르면 e.key 프로퍼티는 'Enter'를 반환하고 abcd를 누르면 e.key프로퍼티는 똑같이 'abcd'를 반환하는 식임.
  - 입력한 키와 key 프로퍼티 값의 대응관계는 keycode.info 참고 ㄱㄱ

6. 이벤트 전파
DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파되는데 이를 이벤트 전파(event propagation)이라고 한다

즉, 클릭 이벤트처럼 뭔가 이벤트가 발생하면 
1) 이벤트 객체가 생성되고
2) 이벤트를 발생시킨 DOM 요소(이벤트 타깃)를 중심으로 DOM트리를 통해 전파된다

ㅇ이벤트 전파 단계 캐치
  1) 이벤트 핸들러 어트리뷰트/프로퍼티 방식
    - 타깃, 버블링 단계의 이벤트만 캐치 가능

  2) addEventListener 메서드 방식
    - 캡처링, 타깃, 버블링 단계의 이벤트 캐치 가능
    - 단, 캡처링 단계를 캐치하려면 3번째 인자를 true로 설정해줘야함

ㅇ그래서 뭐 어쩌라는거임?
이벤트는 이벤트를 발생시킨 이벤트 타깃뿐만 아니라 상위 DOM 요소에서도 캐치할 수 있다는 소린데, 이는 이벤트에 따른 동작 순서 조절은 물론 이벤트 위임으로 메모리를 효율적으로 쓸 수 있는 수단을 제공한다는 점에서 유의미하다.

 

 * 이벤트 패스 : 이벤트가 통과하는 DOM 트리 상의 경로, Event.prototype.composedPath 메서드로 확인 경로

 * 버블링 전파가 안되는 이벤트들 (다 대체재가 있으므로 걱정ㄴㄴ)

    - 포커스 이벤트 : focus, blur

    - 리소스 이벤트 : load, unload, abort, error

    - 마우스 이벤트 : mouseenter, mouseleave

 

근데 사실 캡처링 단계에서 이벤트를 캐치해야 할 경우는 별로 없음 ㅎㅎ;;

 

7. 이벤트 위임(event delegation)
여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법을 말한다

예를들어 <ul> 태그 아래 겁나 많은 <li>태그들이 있다면 <li>태그에 일일이 이벤트 핸들러를 다는게 아니라 <ul> 태그 하나에만 달아주는 방식

<ul id="items">
  <li></li>
  <li></li>
  <li></li>
</ul>

$items = document.getElementById('items');

// { target } 은 e.target을 구조분해 할당한 것
function activate( { target } ) {
    // 타겟이 #items의 자식 요소가 아니라면 무시
    // Element.prototype.matches( 선택자 ) : 선택자
    if (!target.matches('#items > li')) return;
    [ ...$items.children].forEach($item => {
        $items.classList.toggle( 'active', $item === target );
    }
}

$items.onclick = activate;

' > 자바스크립트 딥다이브' 카테고리의 다른 글

[21장] 빌트인 객체  (0) 2022.01.31
[40장] 이벤트(3)  (0) 2022.01.31
[40장] 이벤트  (0) 2022.01.29
[39장] DOM(3)  (0) 2022.01.28
[39장] DOM(2)  (0) 2022.01.27