[모던 자바스크립트 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 이벤트 객체
- 생성된 이벤트 객체는 이벤트 핸들러의 첫번째 인수로 전달된다.
클릭하세요. 클릭한 곳의 좌표가 표시됩니다.
- 이벤트 핸들러 어트리뷰트 방식의 경우 이벤트 객체를 전달받으려면 이벤트 핸들러의 첫번째 매개변수 이름이 반드시 event이어야 한다.
1. 이벤트 객체의 상속 구조
- 이벤트가 발생하면 이벤트 타입에 따라 다양한 타입의 이벤트 객체가 생성된다.
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단계로 구분할 수 있다.
- 캡처링 단계 : 이벤트가 상위 요소에서 하위 요소 방향으로 전파
- 타깃 단계 : 이벤트가 이벤트 타깃에 도달
- 버블링 단계 : 이벤트가 하위 요소에서 상위 요소 방향으로 전파
- 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