일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 99클럽
- 파이썬
- node.js
- 데이터베이스시스템
- 프로그래머스
- redis
- 중간이들
- CSS
- JavaScript
- presignedurl
- TiL
- Python
- 유노코딩
- 코드잇
- 꿀단집
- Cookie
- 코딩테스트
- 파이썬프로그래밍기초
- SQL
- aws
- 항해99
- 엘리스sw트랙
- Git
- 방송대컴퓨터과학과
- 방송대
- nestjs
- 코딩테스트준비
- 개발자취업
- HTML
- MySQL
- Today
- Total
배꼽파지 않도록 잘 개발해요
[코드잇] 인터랙티브 자바스크립트 ② - 이벤트 살펴보기, 다양한 이벤트 본문
3. 이벤트 살펴보기
이벤트 핸들러 등록하기
이벤트 핸들러를 등록할 때 가장 권장되는 방법 : addEventListener
하나의 요소에 여러 개의 독립적인 이벤트 핸들러를 등록할 수 있음.
- Element.addEventListener('type', 'handler')
- Element.removeEventListner('type', 'handler')
removeEventListener 메소드는 파라미터로 전달하는 타입과 이벤트 핸들러가 addEventListener 메소드로 등록할 때와 동일할 때만 이벤트 핸들러를 삭제할 수 있음.
// 이벤트 등록하기
let btn = document.querySelector('#myBtn');
// btn.onclick = function () {
// console.log('Hi Codeit!');
// };
function event1() {
console.log('Hi Codeit!');
}
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);
이벤트 객체
웹사이트에서 이벤트가 발생하면 관련된 정보를 담은 이벤트 객체가 만들어짐.
이벤트 핸들러의 첫번째 파라미터에는 항상 이벤트 객체가 전달됨.
const toDoList = document.querySelector('#to-do-list');
const items = toDoList.children;
// event.target = 이벤트를 발생시킨 요소
function updateToDo(event) {
event.target.classList.toggle('done');
}
// 변경된 이벤트 핸들러 등록: toggleDone 함수 사용
for (let tag of items) {
tag.addEventListener('click', updateToDo);
}
모든 이벤트 객체들이 공통적으로 가지고 있는 프로퍼티
프로퍼티 | 설명 |
type | 이벤트 이름 ('click', 'mouseup', 'keydown' 등) |
target | 이벤트가 발생한 요소 |
currentTarget | 이벤트 핸들러가 등록된 요소 |
timeStamp | 이벤트 발생 시각 (페이지가 로드된 이후부터 경과한 밀리초) |
bubbles | 버블링 단계인지를 판단하는 값 |
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
MouseEvent - Web APIs | MDN
The MouseEvent interface represents events that occur due to the user interacting with a pointing device (such as a mouse). Common events using this interface include click, dblclick, mouseup, mousedown.
developer.mozilla.org
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
KeyboardEvent - Web APIs | MDN
KeyboardEvent objects describe a user interaction with the keyboard; each event describes a single interaction between the user and a key (or combination of a key with modifier keys) on the keyboard. The event type (keydown, keypress, or keyup) identifies
developer.mozilla.org
이벤트 버블링
· 이벤트가 발생한 요소에서 시작하여 계층 구조 상위로 이동하는 현상
· 하나의 요소에 이벤트가 발생하게되면, 이 요소에 할당된 이벤트 핸들러가 동작하고 거기서 끝이 아니라 이어서 같은 타입의 이벤트에 한해서 부모 요소의 핸들러도 동작하게 됨.
· 가장 최상단의 윈도우 객체를 만날 때까지 이 과정이 반복됨.
· 요소 각각의 할당된 모든 이벤트 핸들러가 동작하는 원리임.
ex. item을 클릭 → item의 부모요소인 list, 그 부모요소인 content 이벤트도 쭉 동작함.
· 이벤트 버블링이 일어나도 이벤트 객체의 target 프로퍼티는 변하지 않고, 처음 이벤트가 발생한 시작점을 담고 있음.
· 이벤트 버블링은 이벤트 핸들러가 등록된 요소에서만 전파됨.
event.target
· 버블링 단계에서 현재 이벤트를 발생시킨 요소를 나타냄.
document.getElementById('parent').addEventListener('click', function(event) {
console.log('event.target:', event.target);
});
event.currentTarget
· 이벤트 핸들러가 현재 실행 중인(현재 처리 중인) 요소
· 버블링 단계에서 이벤트를 실행시킨 요소와 다를 수 있음.
document.getElementById('parent').addEventListener('click', function(event) {
console.log('event.currentTarget:', event.currentTarget);
});
버블링을 멈추는 방법
e.stopProparation();
정말 필요한 일이 아니면 이 방법을 쓰지 말자.
페이지 전체에 걸친 이벤트 만들어야 할 때는 버블링이 막혀 있는 구간이 있으면 그 부분만 원하는 이벤트를 얻지 못함.\
버블링의 예시
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>오늘 할 일</title>
</head>
<body>
<div id="main">
<h2 id="title">오늘 할 일</h2>
<ul id="to-do-list">
<li class="item">자바스크립트 공부하기</li>
<li class="item">고양이 화장실 청소하기</li>
<li class="item">고양이 장난감 쇼핑하기</li>
</ul>
</div>
<script src="index.js"></script>
</body>
</html>
event.currentTarget
const main = document.querySelector('#main');
const toDoList = main.lastElementChild;
function printCurrentTarget(event) {
console.log(event.currentTarget);
}
main.addEventListener('click', printCurrentTarget);
for (let child of toDoList.children) {
child.addEventListener('click', printCurrentTarget);
}
A) main이라는 CSS 아이디의 영역에 클릭 이벤트리스너 등록
B) toDoList의 <li>태그 3개에 클릭 이벤트리스너 등록
만약 <li class="item">자바스크립트 공부하기</li>를 누르면
1) B)에 의해 이벤트리스너가 작동함.
→ <li class="item">자바스크립트 공부하기</li>
2) A)와 버블링에 의해 그 상위 태그인 <div>에도 이벤트가 전파됨.
→ <div id="main">...</div>
event.target
const main = document.querySelector('#main');
const toDoList = main.lastElementChild;
function printTarget(event) {
console.log(event.target);
}
main.addEventListener('click', printTarget);
for (let child of toDoList.children) {
child.addEventListener('click', printTarget);
}
만약 <li class="item">자바스크립트 공부하기</li>를 누르면
1) B)에 의해 이벤트리스너가 작동함.
→ <li class="item">자바스크립트 공부하기</li>
2) A)때문에 버블링 작동하여 이벤트를 발생히킨 실제 클릭된 <li>요소 출력됨
→ <li class="item">자바스크립트 공부하기</li>
캡쳐링
• 캡처링 단계 : 이벤트가 하위 요소로 전파되는 단계
• 타깃 단계 : 이벤트가 실제 타깃 요소에 전달되는 단계
• 버블링 단계 : 이벤트가 상위 요소로 전파되는 단계
대부분의 경우에는 버블링의 단계에서 이벤트 핸들러를 처리함.
이벤트 위임
이벤트 위임(Event Delegation) : 자식 요소에서 발생하는 이벤트를 부모 요소에서 다루는 방식
const list = document.querySelector('#list');
for (let item of list.children) {
item.addEventListener('click', function(e) {
const isDone = e.target.classList.contains('done');
if (isDone) {
console.log('밑줄 생겼다가 지워짐');
} else {
console.log('밑줄 없다가 생김');
}
e.target.classList.toggle('done'); // 'done' 클래스가 존재하면 삭제, 안 그러면 추가
새로운 아이템을 추가하는 상황이 발생하게 되면
이 추가된 아이템에는 이벤트 핸들러가 동작하지 않음.
const list = document.querySelector('#list');
for (let item of list.children) {
item.addEventListener('click', function(e) {
e.target.classList.toggle('done');
});
}
const li = document.createElement('li');
li.classList.add('item');
li.textContent = '일기 쓰기';
list.append(li); // 추가된 아이템은 이벤트 동작 X
매번 추가할 때마다 이벤트 핸들러를 새로 등록해야 되는 문제가 있음.
부모 요소인 리스트에 이벤트 핸들러를 하나만 등록해줘도 모든 자식 요소의 이벤트를 다룰 수 있음.
// 이벤트 위임 (Event Delegation)
const list = document.querySelector('#list');
list.addEventListener('click', function(e) {
e.target.classList.toggle('done');
});
const li = document.createElement('li');
li.classList.add('item');
li.textContent = '일기 쓰기';
list.append(li);
그런데, 온전한 자식요소를 제외한 나머지 부모요소를 클릭해도 이벤트 핸들러가 동작함.
• tagName 프로퍼티 : 해당 요소의 태그 이름값을 대문자로 담고 있는 프로퍼티
• classList의 contains메소드 : 파라미터로 전달하는 값이 해당 요소의 클래스 속성에 있는 판단, boolean값
// 이벤트 위임 (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);
/*
버블링 X -> append한 요소에 이벤트 동작 X
li.addEventListener('click', function(e) {
e.stopPropagation();
});
*/
https://developer.mozilla.org/ko/docs/Web/API/Element/classList
Element.classList - Web API | MDN
Element.classList 는 엘리먼트의 클래스 속성의 컬렉션인 활성 DOMTokenList (en-US)를 반환하는 읽기 전용 프로퍼티이다.
developer.mozilla.org
브라우저의 기본 동작
자바스크립트를 활용하면 브라우저의 기본 동작들을 막을 수 있음.
ex. 마우스 오른쪽 버튼을 클릭하면 상황에 맞는 메뉴 창이 뜸, input 태그에 커서를 두고 키보드 키를 누르면 해당 값이 입력됨.
// 브라우저의 기본 동작
const link = document.querySelector('#link');
const checkbox = document.querySelector('#checkbox');
const input = document.querySelector('#input');
const text = document.querySelector('#text');
// 링크 누르면 팝업 뜨면서 메시지 뜸
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('마우스 오른쪽 클릭은 사용할 수 없습니다.');
});
4. 다양한 이벤트 알아보기
마우스 버튼 이벤트
하나의 이벤트 동작에도 여러 개의 이벤트가 발생함.
각 이벤트끼리 순서가 있음.
더블클릭 = 클릭 이벤트 x 2 + 더블클릭
contextmenu (오른쪽버튼) 순서는 운영체제마다 순서가 다름.
마우스 오른쪽 버튼으로 메뉴창이 뜨면 이벤트가 발생하지 않음.
MouseEvent.button
· 0 : 마우스 왼쪽 버튼
· 1 : 마우스 휠
· 2 : 마우스 오른쪽 버튼
MouseEvent.type
· click : 마우스 왼쪽 버튼을 눌렀을 때
· contextmenu : 마우스 오른쪽 버튼을 눌렀을 때
· dblclick : 동일한 위치에서 빠르게 두번 click할 때
· mousedown : 마우스 버튼을 누른 순간
· mouseup : 마우스 버튼을 눌렀다 뗀 순간
// 왼쪽 버튼 = 청기에 up이라는 클래스 속성값 추가
if (e.button === 0) {
flagBlue.classList.add('up');
}
마우스 이동 이벤트
MouseEvent.type
· mousemove : 마우스 포인터가 이동할 때
· mouseover : 마우스 포인터가 요소 밖에서 안으로 이동할 때
· mouseenter : 마우스 포인터가 요소 밖에서 안으로 움직일 때 (버블링 X, 자식요소 계산 X)
· mouseout : 마우스 포인터가 요소 안에서 밖으로 이동할 때
· mouseleave : 마우스 포인터가 요소 안에서 밖으로 움직일 때 (버블링 X, 자식요소 계산 x)
MouseEvent.target : 이벤트가 발생한 요소
MouseEvent.relatedTarget : 이벤트가 발생하기 직전(또는 직후)에 마우스가 위치해 있던 요소
(이동경로 파악 가능함)
요소끼리 이동할 때 mouseout, mouseover 순서대로 이벤트가 2번 발생함.
마우스가 이동할 때 직전 요소에서 빠져나올 때 mouseout이 발생함.
다음 요소로 들어갈 때 mouseover가 발생함.
MouseEvent.clientX, clientY : 화면에 표시되는 창 기준 마우스 포인터 위치
- 보여지는 화면의 좌측 상단의 모서리 위치를 (0, 0)
MouseEvent.pageX, pageY : 웹 문서 전체 기준 마우스 포인터 위치
MouseEvent.offsetX, offsetY : 이벤트가 발생한 요소 기준 마우스 포인터 위치
- 대상의 좌측 상단의 모서리 위치를 (0, 0)
클라이언트와 페이지는 차이가 없는 것처럼 보임.
그래도 스크롤을 내려보면 y값이 조금 차이가 나는 것을 확인할 수 있음.
const box1 = document.querySelector('#box1');
function onMouseMove(e) {
console.log(`client: (${e.clientX}, ${e.clientY})`);
console.log(`page: (${e.pageX}, ${e.pageY})`);
console.log(`offset: (${e.offsetX}, ${e.offsetY})`);
console.log('------------------------------------');
}
box1.addEventListener('mousemove', onMouseMove);
data-title 속성값 있는지 확인
if (e.target.getAttribute('data-title'))
HTML 태그의 비표준속성에 접근하므로 DOM의 dataset data-* 형태로 작성
if (e.target.dataset.title)
e.target은 HTML 요소 객체로, 이벤트가 발생한 요소
문자열과 비교하려면 e.target.tagName, e.target.className, e.target.id 사용하기
if (e.target === 'title') // X
if (e.target.tagName === 'title') // O
그런데 비표준속성이라서 그런가 안 됨.
키보드 이벤트
KeyboardEvent.type
· keydown: 키보드 버튼을 누른 순간
· keypress: 키보드 버튼을 누른 순간
- 출력값이 변하는 key(알파벳, 숫자, 스페이스바)에서만 이벤트가 발생 O
- 기능적인 역할을 하는 key(esc, shift)에는 이벤트 발생 X
- 출력값이 변하더라도 영어가 아니면 반응하지 않음
- 웹표준에서는 권장하지 않음
· keyup: 키보드 버튼을 눌렀다 뗀 순간
하나의 키를 계속 누르고 있는 상황
→ keypress 1번, keydown 연속적 발생
KeyboardEvent.key
: 이벤트가 발생한 버튼의 값
KeyboardEvent.code
: 이벤트가 발생한 버튼의 키보드에서 물리적인 위치
function sendMyTextByEnter (e) {
if (e.key === 'Enter' && !e.shiftKey) {
sendMyText();
}
}
input.addEventListener('keypress', sendMyTextByEnter);
input 태그 다루기
포커스 이벤트
· focusin: 요소에 포커스가 되었을 때
· focusout: 요소에 포커스가 빠져나갈 때
· focus: 요소에 포커스가 되었을 때 (버블링 x)
· blur: 요소에 포커스가 빠져나갈 때 (버블링 x)
입력 이벤트
· input: 사용자가 입력을 할 때
· change: 요소의 값이 변했을 때 (입력이 시작되기 전 값과 완료되었을 때 값에 차이가 있었을 때만)
input 태그의 테두리가 파란색 테두리로 강조됨 = focus됨. = 사용자의 동작에 반응할 준비가 되었음.
어떤 값이 입력될 때 발생하기 때문에 esc나 shift 같은 입력과 관게없는 키에는 이벤트가 발생하지 않음.
일반적으로 focus가 빠져나갔을 때 입력이 완료됐다고 판단해서 change 이벤트가 focusout 직전에 발생함.
const el = document.querySelector('#form');
function printEventType(e) {
console.log('type:', e.type);
console.log('target:', e.target);
console.log('---------');
}
el.addEventListener('focusin', printEventType);
el.addEventListener('focusout', printEventType);
el.addEventListener('input', printEventType);
el.addEventListener('change', printEventType);
[data-word="${input.value}"]
· "data-word" 속성의 값이 input 요소의 현재 값과 일치하는 요소를 선택
· 즉, 현재 입력 필드의 값과 동일한 값을 가진 요소를 찾는 것
· 만약 input의 현재 값이 "apple"이라면, [data-word="apple"]와 일치하는 요소를 찾게 됨.
function removeElement() {
// 입력값과 일치하는 단어를 가진 요소 찾기
const matchingElement = document.querySelector(`[data-word="${input.value}"]`);
// 일치하는 요소가 있으면 삭제
if (matchingElement) {
matchingElement.remove();
// checker 함수 호출
checker();
// input값 초기화
input.value = ''
}
}
addEventListener('change', removeElement)
input 대신 change를 쓰는 이유
· text 타입의 input 태그에서는 Enter 키를 누르는 것으로도 change 이벤트를 발생시킴.
· removeElement에서 input의 내용을 초기화하고 있음.
· 값이 입력될 때마다 이벤트가 발생하는 input보다는 입력된 값이 바뀔 때 발생하는 change를 쓰는게 더 효율적임.
스크롤 이벤트
일반적으로는 웹 문서의 크기가 브라우저의 창 크기보다 클 때 브라우저에 자연스럽게 나타남.
스크롤이벤트는 이 브라우저를 대변하는 윈도우 객체의 이벤트 핸들러에 등록함.
function printEvent(e) {
console.log(e);
}
window.addEventListener('scroll', printEvent);
scrollY : 웹 문서의 젤 위쪽에서부터 몇 픽셀만큼 스크롤했는지 파악할 수 있음.
'코드잇 Codeit > Front-End' 카테고리의 다른 글
[코드잇] 자바스크립트 웹 개발 기본기 ② - 비동기 실행과 Promise 객체 (0) | 2023.12.29 |
---|---|
[코드잇] 자바스크립트 웹 개발 기본기 ① - 웹 기초 다지기, Web API 배우기 (0) | 2023.12.26 |
[코드잇] 인터랙티브 자바스크립트 ① 시작하기, 브라우저와 자바스크립트 (1) | 2023.12.23 |
[코드잇] HTML 핵심 개념 ② 링크, 텍스트, 리스트, 테이블 (0) | 2023.12.20 |
[코드잇] HTML 핵심 개념 ① - 링크, 텍스트, 리스트, 테이블 (0) | 2023.12.20 |