인터랙티브 JS (3)

깨진알·2023년 12월 11일

JavaScript

목록 보기
9/21

이벤트 살펴보기

1. 이벤트 핸들러 등록하기

// 이벤트 등록하기
let btn = document.querySelector('#myBtn');

btn.onclick = function () {
	console.log('Hi Cracked_Egg!');
};

function event1() {
	console.log('Hi Cracked_Egg!');
}

function event2() {
	console.log('Hi again!');
}

// elem.addEventListener(event, handler)
btn.addEventListener('click', event1);
btn.addEventListener('click', event2);

// elem.removeEventListener(event, handler)
btn.removeEventListener('click', event2);

addEventListener를 통해 하나의 요소에 여러 이벤트 핸들러를 설정할 수 있게 된다. 또한 removeEventListener 메소드를 사용할 때는 등록했던 핸들러를 사용해야 한다.


2. 다양한 이벤트

(1) 마우스 이벤트

이벤트 타입 설명
mousedown 마우스 버튼을 누르는 순간
mouseup 마우스 버튼을 눌렀다 때는 순간
click 왼쪽 버튼을 클릭한 순간
dblclick 왼쪽 버튼을 빠르게 두 번 클릭한 순간
contextmenu 오른쪽 버튼을 클릭한 순간
mousemove 마우스를 움직이는 순간
mouseover 마우스 포인터가 요소 위로 올라온 순간
mouseout 마우스 포인터가 요소에서 벗어나는 순간
mouseenter 마우스 포인터가 요소 위로 올라온 순간 (버블링이 일어나지 않음)
mouseleave 마우스 포인터가 요소에서 벗어나는 순간 (버블링이 일어나지 않음)

(2) 키보드 이벤트

이벤트 타입 설명
keydown 키보드의 버튼을 누르는 순간
keypress 키보드의 버튼을 누르는 순간 ('a', '5' 등 출력이 가능한 키에서만 동작하며, Shift, Esc 등의 키에는 반응하지 않음)
keyup 키보드의 버튼을 눌렀다 때는 순간

(3) 포커스 이벤트

이벤트 타입 설명
focusin 요소에 포커스가 되는 순간
focusout 요소로부터 포커스가 빠져나가는 순간
focus 요소에 포커스가 되는 순간 (버블링이 일어나지 않음)
blur 요소로부터 포커스가 빠져나가는 순간 (버블링이 일어나지 않음)

(4) 입력 이벤트

이벤트 타입 설명
change 입력된 값이 바뀌는 순간
input 값이 입력되는 순간
select 입력 양식의 하나가 선택되는 순간
submit 폼을 전송하는 순간

(5) 스크롤 이벤트

이벤트 타입 설명
scroll 스크롤 바가 움직일 때

(6) 윈도우 창 이벤트

이벤트 타입 설명
resize 윈도우 사이즈를 움직일 때 발생

3. 이벤트 객체 프로퍼티

// 이벤트 객체 (Event Object)
const myInput = document.querySelector('#myInput');
const myBtn = document.querySelector('#myBtn');

function printEvent(event) {
	console.log(event);
	event.target.style.color = 'red';
}

myInput.addEventListener('keydown', printEvent);
myBtn.addEventListener('click', printEvent);

이벤트 핸들러의 첫번째 파라미터에는 자동으로 이벤트 객체가 전달된다. 자주 사용되는 이벤트 객체의 프로퍼티들에 대해 알아보자.

(1) 공통 프로퍼티

프로퍼티 설명
type 이벤트 이름 ('click', 'mouseup', 'keydown' 등)
target 이벤트가 발생한 요소
currentTarget 이벤트 핸들러가 등록된 요소
timeStamp 이벤트 발생 시각 (페이지가 로드된 이후부터 경과한 밀리초)
bubbles 버블링 단계인지를 판단하는 값

(2) 마우스 이벤트

프로퍼티 설명
button 누른 마우스의 버튼 (0: 왼쪽, 1: 가운데(휠), 2: 오른쪽)
clientX, clientY 마우스 커서의 브라우저 표시 영역에서의 위치
pageX, pageY 마우스 커서의 문서 영역에서의 위치
offsetX, offsetY 마우스 커서의 이벤트 발생한 요소에서의 위치
screenX, screenY 마우스 커서의 모니터 화면 영역에서의 위치
altKey 이벤트가 발생할 때 alt키를 눌렀는지
ctrlKey 이벤트가 발생할 때 ctrl키를 눌렀는지
shiftKey 이벤트가 발생할 때 shift키를 눌렀는지
metaKey 이벤트가 발생할 때 meta키를 눌렀는지 (window는 window키, mac은 cmd키)

(3) 키보드 이벤트

프로퍼티 설명
key 누른 키가 가지고 있는 값
code 누른 키의 물리적인 위치
altKey 이벤트가 발생할 때 alt키를 눌렀는지
ctrlKey 이벤트가 발생할 때 ctrl키를 눌렀는지
shiftKey 이벤트가 발생할 때 shift키를 눌렀는지
metaKey 이벤트가 발생할 때 meta키를 눌렀는지 (window는 window키, mac은 cmd키)

4. 이벤트 버블링

// 이벤트 버블링 (Event Bubbling)
const content = document.querySelector('#content');
const title = document.querySelector('#title');
const list = document.querySelector('#list');
const items = document.querySelectorAll('.item');

content.addEventListener('click', function(e) {
  console.log('content Event');
  console.log(e.currentTarget);
});

title.addEventListener('click', function(e) {
  console.log('title Event');
  console.log(e.currentTarget);
});

list.addEventListener('click', function(e) {
  console.log('list Event');
  console.log(e.currentTarget);
});

for (let item of items) {
  item.addEventListener('click', function(e) {
    console.log('item Event');
    console.log(e.currentTarget);
		e.stopPropagation();
  });
}

이벤트 버블링의 원리는 하나의 요소에 이벤트가 발생하면 할당된 이벤트 핸들러가 동작하고 부모 요소의 핸들러도 동작하게 되며, 최상단의 윈도우 객체를 만날때까지 반복되게 되어 모든 이벤트 핸들러가 동작하게 되는 것이다.

target 프로퍼티는 변하지 않고 있어, 처음 이벤트의 시작점에 접근할 수 있다. 만약 이벤트 핸들러가 등록된 요소에 접근하고 싶을 때는 currentTarget 프로퍼티를 사용하면 된다.

버블링을 멈추기 위해서는 stopPropagation 프로퍼티를 사용하면 된다. 하지만 버블링을 멈추어야 할 특수한 상황이 아니면 가급적 사용하지 않는 것을 추천한다.


5. 캡쳐링

표준 DOM 이벤트에서 정의한 이벤트 흐름에는 3가지 단계가 있다.
1. 캡쳐링 단계: 이벤트가 하위 요소로 전파되는 단계
2. 타깃 단계: 이벤트가 실제 타깃 요소에 전달되는 단계
3. 버블링 단계: 이벤트가 상위 요소로 전파되는 단계

버블링 단계는 위에서 설명했던 내용이며, 타깃 단계는 이벤트 객체의 target 프로퍼티가 되는 요소에 등록되어 있던 이벤트 핸들러가 동작하는 단계인데, 쉽게 생각해서 가장 처음 이벤트 핸들러가 동작하게 되는 순간이라고 생각하면 된다.

  • 캡쳐링
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8">
    <title>JS with Codeit</title>
  </head>
  <body>
    <div id="content">
      <h1 id="title">오늘 할 일</h1>
      <ol id="list">
        <li class="item">자바스크립트 공부</li>
        <li class="item">독서</li>
      </ol>
    </div>
    <script src="index.js"></script>
  </body>
</html>

위 코드에서 '자바스크립트 공부'를 클릭한다면, 버블링은 li태그부터, ol태그, div태그, body태그, html태그, document태그, window객체로 이벤트가 전파가 된다. 캡쳐링은 이벤트가 발생하면 가장 먼저, 그리고 버블링의 반대 방향으로 진행되는 이벤트 전파 방식이다.

이벤트가 발생하면 가장 먼저 window객체에서부터 target까지 이벤트 전파가 일어난다. (캡쳐링 단계) 그리고 타깃에 도달하면 타깃에 등록된 이벤트 핸들러가 동작하고, (타깃 단계) 이후 다시 window객체로 이벤트가 전파된다. (버블링 단계) 이런 과정을 통해 각 요소에 할당된 이벤트 핸들러가 호출되게 된다.

캡쳐링 단계에서 이벤트를 발생시켜야 하는 일은 매우 드물다. 보통 타깃 단계에서 target에 등록된 이벤트 핸들러가 있으면 해당 이벤트 핸들러가 먼저 동작한 이 후에 버블링 단계에서 각 부모 요소에 등록된 이벤트 핸들러가 있으면 그 때 해당 이벤트 핸들러가 동작하는 것이 일반적이다.

하지만 상황에 따라서 캡쳐링 단계에서 부모 요소의 이벤트 핸들러를 동작시켜야 할 때도 있다. 캡쳐링 단계에서 이벤트 핸들러를 동작시키려면, addEventListener에 세번째 프로퍼티에 true 또는 {captrue: true}를 전달하면 된다.


6. 이벤트 위임

// 이벤트 위임 (Event Delegation)
const list = document.querySelector('#list');

list.addEventListener('click', function(e) {
	// if (e.target.tagName === 'LI')
	if (e.target.classList.contains('item')) {
		e.target.classList.toggle('done');
	}
});

const li = document.createElement('li');
li.classList.add('item');
li.textContent = '일기 쓰기';
list.append(li);

li.addEventListener('click', function(e) {
  e.stopPropagation();
});

버블링 개념을 활용하면 훨씬 효과적인 이벤트 관리를 할 수 있게 된다. 예를 들어 자식 요소 각각에 이벤트 핸들러를 하나씩 등록할 필요 없이 부모 요소에서 한 번에 자식 요소들에 발생한 이벤트를 관리할 수 있다. 이렇게 이벤트를 다루는 방식을 자식 요소의 이벤트를 부모 요소에 위임한다고 해서 '이벤트 위임'이라고 부른다.


7. 브라우저의 기본 동작

// 브라우저의 기본 동작
const link = document.querySelector('#link');
const checkbox = document.querySelector('#checkbox');
const input = document.querySelector('#input');
const text = document.querySelector('#text');

// event.preventDefault
link.addEventListener('click', function(e) {
	e.preventDefault();
	alert('지금은 이동할 수 없습니다.');
});

input.addEventListener('keydown', function(e) {
	if (!checkbox.checked) {
		e.preventDefault();
		alert('체크박스를 먼저 체크해 주세요.');
	}
});

document.addEventListener('contextmenu', function(e) {
	e.preventDefault();
	alert('마우스 오른쪽 클릭은 사용할 수 없습니다.');
});
profile
프론트엔드 지식으로 가득찰 때까지

0개의 댓글