blair's 개발 portfolio

[모던 자바스크립트 Deep Dive] 40. 이벤트

40. 이벤트 

 

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

  • 이벤트가 발생했을 때 호출될 함수를 이벤트 핸들러라 하고, 이벤트가 발생했을 때 브라우저에게 이벤트 핸들러의 호출을 위임하는 것을 이벤트 핸들러 등록이라 한다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>Click me!</button>
    <script>
        const button = document.querySelector('button');
        button.onclick = () => {alert('button click'); }
    </script>
</body>
</html>
  • 이벤트와 그에 대응는 함수(이벤트 핸들러)를 통해 사용자와 애플리케이션은 상호작용을 할 수 잇따. 이와 같이 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식을 이벤트 드리븐 프로그래밍이라 한다.

 

40.2 이벤트 타입

  • 이벤트 타입은 이벤트의 종류를 나타 내는 문자열

1. 마우스 이벤트

2. 키보드 이벤트

3. 포커스 이벤트

4. 폼 이벤트

5. 값 변경 이벤트

6. DOM 뮤테이션 이벤트

7. 뷰 이벤트

8. 리소스 이벤트

40.3 이벤트 핸들러 등록

  • 이벤트 핸들러는 이벤트가 발생했을 때 브라우저에 호출을 위임한 함수
  • 이벤트가 발생했을 때 브라우저에게 이벤트 핸들러의 호출을 위임하는 것을 이벤트 핸들러 등록이라 한다

 

1. 이벤트 핸들러 어트리뷰트 방식

  • on 접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있다.
  • 이벤트 핸들러 어트리뷰트 값으로 험수 호출문 등의 문을 할당하면 이벤트 핸들러가 등록된다.
  • 함수호출을 브라우저에게 위임하는 것
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button onclick="sayHi('Lee')">Click me!</button>
    <script>
        function sayHi(name) {
            console.log(`Hi! ${name}.`)
        }
    </script>
</body>
</html>

 

2. 이벤트 핸들러 프로퍼티 방식

  • 이벤트 핸들러 어트리뷰트와 마찬가지로 onclick과 같이 on 접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있다.
  • 프로퍼티에 함수를 바인딩하면 이벤트 핸들러가 등록된다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>Click me!</button>
    <script>
        const $button = document.querySelector('button');

        //이벤트 핸들러 프로퍼티에 이벤트 핸들러를 바인딩
        $button.onclick = function(){
            console.log('button click');
        }
    </script>
</body>
</html>
  • 이벤트 핸들러를 등록하기 위해서는 이벤트를 발생시킬 객체인 이벤트 타깃과 이벤트의 종류를 나타내는 문자열인 이벤트 타입 그리고 이벤트 핸들러를 지정할 필요가 있다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>Click me!</button>
    <script>
        const $button = document.querySelector('button');

        //이벤트 핸들러 프로퍼티 방식은 하나의 이벤트에 하나의 이벤트 핸들러만을 바인딩할 수 있다
        // 첫번째로 바인딩 된 이벤트 핸들러는 두번째 바인딩된 이벤트 핸들러에 의해 재할당되어 실행되지 않는다.

        $button.onclick = function(){
            console.log('button clicked 1');
        }

        //두번째로 바인딩 된 이벤트 핸들러
        $button.onclick = function(){
            console.log('button clicked 2');
        }
    </script>
</body>
</html>

3. addEventListener 메서드 방식

  • EventTarget.prototype.addEventListener 메서드를 사용하여 이벤트 핸들러를 등록할 수 있다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>Click me!</button>
    <script>
        const $button = document.querySelector('button');

        $button.addEventListener('click' , function(){
            console.log('button click')
        })
    </script>
</body>
</html>

40.4 이벤트 핸들러 제거

  • EventTarget.prototype.removeEventListener 메서드를 사용한다.
  • addEventListener 메서드에 인수로 전달한 등록 인벤트 핸들러야 삭제가 된다

40.5 이벤트 객체

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

클릭하세요. 클릭한 곳의 좌표가 표시됩니다.

  • 이벤트 핸들러 어트리뷰트 방식의 경우 이벤트 객체를 전달받으려면 이벤트 핸들러의 첫번째 매개변수 이름이 반드시 event이어야 한다.

 

1. 이벤트 객체의 상속 구조

  • 이벤트가 발생하면 이벤트 타입에 따라 다양한 타입의 이벤트 객체가 생성된다.

Document

2. 이벤트 객체의 공통 프로퍼티

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

3. 마우스 정보 취득

  • click, dbclick, mousedown, mouseup, mousemove,mouseenter,mouseleave 이벤트가 발생하면 생성되는 MouseEvent 타입의 이벤트 객체는 다음과 같은 고유 프로퍼티를 갖는다.

4. 키보드 정보 취득

  • ketdown, keyup, keypress 이벤트가 발생하면 생성되는 KeyboardEvent 타입의 이벤트 객체는 altKey, ctrlKey, shiftKey, metaKey, key,keycoDE 같은 고유의 프로퍼티를 갖는다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text">
    <em class="message"></em>
    <script>
        const $input = document.querySelector('input[type=text]');
        const $msg = document.querySelector('.message');

        $input.onkeyup = e => {
            //e.key는 입력한 키 값을 문자열로 반환한다.
            //입력한 키가 'Enter' 즉 엔터 키가 아니면 무시한다
            if(e.key !== 'Enter') return;

            //엔터키가 입력되면 현재까지 입력 필드에 입력된 값을 출력한다
            $msg.textContent = e.target.value;
            e.target.value = ''
        }
    </script>
</body>
</html>

40.6 이벤트 전파

  • DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파된다.
  • 이를 이벤트 전파라고 함
  • 생성된 이벤트 객체는 이벤트를 발생시킨 DOM 요소인 이벤트 타깃을 중심으로 DOM 트리를 통해 전파된다
  • 이벤트 객체가 전파되는 방향에 따라 다음과 같이 3단계로 구분할 수 있다.
  • 캡처링 단계 : 이벤트가 상위 요소에서 하위 요소 방향으로 전파
  • 타깃 단계 : 이벤트가 이벤트 타깃에 도달
  • 버블링 단계 : 이벤트가 하위 요소에서 상위 요소 방향으로 전파
Document
  • Apple
  • 이벤트는 이벤트를 발생시킨 이벤트 타킷은 물론 상위 DOM 요소에서도 캐치할 수 있다.
  • 즉, DOM 트리를 통해 전파되는 이벤트는 이벤트 패스에 위치한 모든 DOM 요소에서 캐치할 수 있다.
  • 대부분의 이벤트는 캡처링과 버블링을 통해 전파된다.

  • 위 이벤트는 버블링이 되지 않으므로 이벤트 타깃의 상위 요소에서 위 이벤트를 캐치하려면 캡처링 단계의 이벤트를 캐치

40.7 이벤트 위임

 

  • 여러개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법을 말한다.
  • 주의할점은 상위 요소에 이번트 핸들러를 등록하기 때문에 이벤트 타깃, 즉 이벤트를 실제로 발생시킨 DOM 요소가 기대한 DOM 요소가 아닌 수 있다.
  • Element.prototype.matches 메서드는 인수로 전달된 선택자에 의해 특정 노드를 탐색 가능한지 확인

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <style>
        #fruits {
            display: flex;
            list-style-type: none;
            padding: 0;
        }
        #fruits li{
            width: 100px;
            cursor: pointer;
        }
        #fruits .active{
            color: red;
            text-decoration: underline;
        }
    </style>
    <ul id="fruits">
        <li id="apple">Apple</li>
        <li id="banana">banana</li>
        <li id="orange">orange</li>
    </ul>
    <div>선택된 네비게이션 아이템 <em class="msg">apple</em></div>
    <script>
        const $fruits = document.getElementById('fruits');
        const $apple = document.getElementById('apple');

        //사용자 클릭에 의해 선택된 네비게이션 아이템에 active 클래스를 추가하고
        // 그외의 모든 네비게이션 아이템의 active 클래스를 제거한다
        function activate({target}){
            if(!target.matches('fruits > li')) return;

            [...$fruits.children].forEach($fruit => {
                $fruit.classList.toggle('active', $fruit === target);
                $msg.textContent = target.id;
            })
        }
        // 이벤트 위임 : 삿ㅇ위 요소는 하위 요소의 이벤트를 캐치할 수 잇다
        $fruits.onclick = activate;
    </script>
</body>
</html>

40.8 DOM 요소의 기본 동작 조작

1. DOM 요소의 기본 동작 중단

  • 이벤트 객체의 preventDefault 메서드는 DOM 요소의 기본 동작을 중단 시킨다.

2. 이벤트 전파 방지

  • stopPropagation 이벤트 전파를 중지 시킨다.

40.9 이벤트 핸들러 내부의 this

1. 이벤트 핸들러 어트리뷰트 방식

  • handleClcik 함수 내부의 this는 전역 객체 window를 가르킨다 
  • 단 이벤트 핸들러를 호출할 때 인수로 전달한 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.

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

  • addEventListener 메서드 방식 모두 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.
  • 이벤트 핸들러 내부의 this는 이벤트 객체의 currenTarget 프로퍼티와 같다.
  • 화살표 함수로 정의한 이벤트 핸들러 내부의 this는 상위 스코프의 this를 가리킨다.
  • 화살표 함수는 함수 자체의 this 바인딩을 갖지 않는다.

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

  • 함수에 인수를 전달하려면 함수를 호출할때 전달해야 한다.
  • 이벤트 핸들러 어트리뷰트 방식은 함수 호출문을 사용할 수 있기 때문에 인수전달 가능,
  • 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식의 경우 이벤트 핸들러를 브라우저가 호출하기 때문에 함수 호출문이 아닌 함수 자체를 등록해야 한다. => 인수를 전달 할 수 없다.
  • 이벤트 핸들러 내부에서 함수를 호출하면서 인수 전달 가능
  • 반환하는 함수를 호출하면서 인수를 전달할 수도 있다.
  • checkUserNameLength  함수는 함수를 반환

 

40.11 커스텀 이벤트

1. 커스텀 이벤트 생성

  • CustomEvent 이벤트 생성자 함수를 사용 한다
const keyboardEvent = new KeyboardEvent('keyup');
console.log(keyboardEvent.type);//keyup

const customEvent = new CustomEvent('foo');
console.log(customEvent.type);//foo
  • 버블링되지 않으며 preventDefault 메서드로 취소할 수도 없다.
  • 커스텀 이벤트 객체는 bubbles와 cancelable 프로퍼티의 값이 false로 기본 설정된다.
const customEvent = new MouseEvent('click', {
    bubbles : true,
    cancelable : true
});

console.log(customEvent.bubbles); //true
console.log(customEvent.cancelable); //true
  • 커스텀 이벤트 객체의 bubbles 또는 프로퍼티를 true로 설정하려면 이벤트 생성자 함수의 두번째 인수로 bubbles 또는 cancelable 프로퍼티를 갖는 객체를 전달한다.

2. 커스텀 이벤트 디스패치

  • dispatchEvent 메서드로 디스패치(이벤트를 발생시키는 행위)할 수 있다.
  • dispatchEvent 메서드에 이벤트 객체를 인수로 전달하면서호출하면 인수로 전달한 이벤트 타입의 이벤트가 발생한다.
  • 이벤트 핸들러를 동기 처리 방식으로 호출
  • 디스패치를 하기 이전에 커스텀 이벤트를 처리할 이벤트 핸들러를 등록해야한다.

 

블로그의 정보

개발 블로그👩‍💻

Blairj

활동하기