본문 바로가기
혼공학습단 11기(完)

[혼공스] 07 - 2 '이벤트 활용' 정리(1)

by jaeheon0520 2024. 2. 2.

 

오늘은 07 - 2장의 내용을 정리해 보자.

 

07 - 2장의 제목은 '이벤트 활용'으로, 간단한 애플리케이션을 구현하는 이벤트와 관련된 내용을 다루고 있다.

 

이벤트 모델

이벤트를 연결하는 방법을 이벤트 모델이라고 부른다.

 

07 -1 장에서는 이벤트를 연결할 때 addEventListener() 메소드를 사용했다. 이 방법이 현재 표준으로 사용하고 있는 방법이므로 표준 이벤트 모델이라고 부른다.

 

document.body.addEventListener('keyup', () => {

})

 

과거에는 다음과 같이 문서 객체가 갖고 있는 onOO으로 시작하는 속성에 함수를 할당해서 이벤트를 연결했다. 이와 같은 이벤트 연결 방법을 고전 이벤트 모델이라고 부른다.

 

document.body.onkeyup = (event) => {

}

 

그리고 고전 이벤트 모델처럼 onOO으로 시작하는 속성을 HTML 요소에 직접 넣어서 이벤트를 연결하는 것을 인라인 이벤트 모델이라고 부른다.

 

<script>
    const listener = (event) => {
    
    }
</script>
<body onkeyup="listener(event)">

</body>

 

인라인 이벤트 모델은 HTML 요소의 onOO 속성에 자바스크립트 코드를 넣는 것이다. 현재 코드에서는 listener()라는 함수를 호출하고 있다. 이때 onOO 속성 내부에서 변수 event를 활용할 수 있다. 이 변수를 listener() 함수의 매개변수로 전달한다.

 

모든 이벤트 모델의 이벤트 리스너는 첫 번째 매개변수로 이벤트 객체(event object)를 받는다. 이벤트 객체에는 이벤트와 관련된 정보가 들어있다.

 

키보드 이벤트

키보드 이벤트는 다음과 같은 3가지 이벤트가 있다.

 

이벤트 설명  
keydown 키가 눌릴 때 실행된다. 키보드를 꾹 누르고 있 때도, 입력될 때도 실행된다.
keypress 키가 입력되었을 때 실행된다. 하지만 웹 브라우저에 따라서 아시아권의 문자를 제대로 처리하지 못하는 문제가 있다.
keyup 키보드에서 키가 떨어질 때 실행된다.

 

keydown 이벤트와 keypress 이벤트는 웹 브라우저에 따라서 아시아권 문자(한국어, 중국어, 일본어)를 제대로 처리하지 못하는 문제가 있어서 일반적으로는 keyup 이벤트를 사용한다.

 

간단하게 키보드 이벤트로 입력 양식의 글자 수를 세는 프로그램을 만들어보자. 다음 프로그램은 textarea에 keyup 이벤트를 적용해서 입력한 글자 수를 세는 프로그램이다. textarea처럼 텍스트를 입력하는 양식의 값은 value 속성으로 읽어 들인다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const textarea = document.querySelector('textarea')
            const h1 = document.querySelector('h1')

            textarea.addEventListener('keyup', (event) => {
                const length = textarea.value.length // value 속성으로 입력 양식의 글자를 읽어들일 수 있다
                h1.textContent = `글자 수: ${length}`
            })
        })
    </script>
</head>
<body>
    <h1>글자 수 : 0</h1>
    <textarea></textarea>
</body>
</html>

 

글자 수 출력하기

 

keydown 이벤트는 특정 상황(ex. ㅋㅋ)에서 글자를 세지 못한다는 문제가 있었고, keypress 이벤트는 공백이 들어가기 전까지는 글자 수를 세지 못한다는 문제가 있었다.(두 이벤트 모두 아시아권 언어에서 문제가 발생)

keyup 이벤트도 문제가 있다. 키가 키보드에서 떨어질 때 발생하므로 특정 키를 꾹 누르고 있으면 글자 수를 세지 않는다. 이를 해결하기 위해 트위터는 키보드 이벤트를 사용하지 않고 글자 수를 세고 있는데 어떻게 구현했는지 이따가 살펴보도록 하자.

 

키보드 키 코드 사용하기

 

키보드 이벤트가 발생할 때는 이벤트 객체로 어떤 키를 눌렀는지와 관련된 속성들이 따라온다.

 

이벤트 속성 이름 설명
code 입력한 키
keyCode 입력한 키를 나타내는 숫자
altKey Alt 키를 눌렀는지
ctrlKey Ctrl 키를 눌렀는지
shiftKey Shift 키를 눌렀는지

 

code 속성은 입력한 키를 나타내는 문자열이 들어있고, altKey, ctrlKey, shiftKey 속성은 해당 키를 눌렀는지 불 자료형 값이 들어있다. 어떤 의미인지 간단하게 속성들을 출력하는 프로그램을 만들어서 살펴보자. 다음 코드는 keydown이벤트와 keyup이벤트가 발생할 때 표에서 설명한 속성을 모두 출력하는 프로그램이다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const h1 = document.querySelector('h1')
            const print = (event) => {
                let output = ''
                output += `alt: ${event.altKey}<br>` // 이벤트가 발생하면 불 값을 반환한다
                output += `ctrl: ${event.ctrlKey}<br>` // 이벤트가 발생하면 불 값을 반환한다
                output += `shift: ${event.shiftKey}<br>` // 이벤트가 발생하면 불 값을 반환한다
                output += `code: ${typeof(event.code) !== 'undefined' ?
                    event.code : event.keyCode}<br>` // event.code가 있으면, event.code를 출력하고, undefined라면 event.Keycode를 출력한다.
                h1.innerHTML = output
            }

            document.addEventListener('keydown', print) // 키가 눌릴 때 출력한다
            document.addEventListener('keyup', print) // 키가 떨어질 때 출력한다
        })
    </script>
</head>
<body>
    <h1></h1>
</body>
</html>

 

키보드 이벤트 속성 활용

 

페이스북과 트위터 등과 같은 현대적인 소셜 네트워크 사이트는 여러 단축키를 사용할 수 있다. 이러한 단축키를 구현할 때 키보드 이벤트 속성을 사용한 것이다.

 

위 코드에서 'event.code가 있는 경우'를 확인하는 코드를 사용했는데, 이는 인터넷 익스플로러와 구 버전의 엣지 브라우저를 지원하기 위해서이다. 이런 웹 브라우저까지 지원하려면 KeyCode 속성을 활용해서 프로그램을 구현해야 한다.

 

이벤트 발생 객체

지금까지는 이벤트 내부에서 문서 객체 변수를 사용해 문서 객체와 관련된 정보를 추출했다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const textarea = document.querySelector('textarea')
            const h1 = document.querySelector('h1')

            textarea.addEventListener('keyup', (event) => {
                const length = textarea.value.length // value 속성으로 입력 양식의 글자를 읽어들일 수 있다
                h1.textContent = `글자 수: ${length}`
            })
        })
    </script>
</head>
<body>
    <h1>글자 수 : 0</h1>
    <textarea></textarea>
</body>
</html>

 

전에 사용했던 글자 수 세기 프로그램을 살펴보면, textarea는 문서 객체 변수로 문서 객체의 value 속성을 추출했다. 그런데 상황에 따라서는 이벤트 리스너 내부에서 그러한 변수에 접근할 수 없는 경우가 있다. 예를 들어 다음과 같은 코드에서는 listener() 함수 내부에서 textarea 변수에 접근할 수 없어 오류가 발생한다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script>
        const listener = (event) => {
            const length = textarea.value.length // 현재 블록에서는 textarea 변수를 사용할 수 없다.
            h1.textContent = `글자 수: ${length}`
        }

        document.addEventListener('DOMContentLoaded', () => {
            const textarea = document.querySelector('textarea')
            const h1 = document.querySelector('h1')
            textarea.addEventListener('keyup', listener)
        })
    </script>
</head>
<body>
   
</body>
</html>

 

코드 규모가 커지면 이처럼 이벤트 리스너를 외부로 분리하는 경우가 많아진다. 이러한 경우에는 이벤트를 발생시킨 객체(현재 코드의 textarea)에 어떻게 접근할 수 있을까?

 

2가지 방법이 있다.

 

첫째, event.currentTarget 속성을 사용한다.

이는 () => {}와 function () {} 형태로 함수를 선언한 경우에 사용한다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script>
        const listener = (event) => {
            const length = event.currentTarget.value.length // event.currentTarget가 textarea가 된다.
            h1.textContent = `글자 수: ${length}`
        }

        document.addEventListener('DOMContentLoaded', () => {
            const textarea = document.querySelector('textarea')
            const h1 = document.querySelector('h1')
            textarea.addEventListener('keyup', listener)
        })
    </script>
</head>
<body>
   
</body>
</html>

 

위 코드에서 event.currentTarget은 이벤트 헨들러(listener 함수)가 현재 연결되어있는 요소를 의미한다. 현재 listener 함수는 textarea 요소에 keyup 이벤트가 발생할 때 연결되어 있으므로, event.currentTarget가 textarea가 된다.

 

둘째, this 키워드를 사용한다.

화살표 함수가 아닌 function () {} 형태로 함수를 선언한 경우에 사용한다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
    <script>
        const listener = function (event) {
            const length = this.value.length // this가 textarea가 된다.
            h1.textContent = `글자 수: ${length}`
        }

        document.addEventListener('DOMContentLoaded', () => {
            const textarea = document.querySelector('textarea')
            const h1 = document.querySelector('h1')
            textarea.addEventListener('keyup', listener)
        })
    </script>
</head>
<body>
    <h1></h1>
    <textarea></textarea>
</body>
</html>

 

화살표 함수가 없었던 과거에는 2번째 방법을 많이 사용했다. 하지만 화살표 함수가 등장한 이후로는 2가지 방법 모두 많이 사용한다. 2가지 방법 모두 기억해 두자.

 

뒷부분에 나오는 입력 양식은 내용이 상당히 길어지므로 잠깐 쉬어가자.

 

오늘 하루도 쌓였다.