인터랙티브 JS (4)

깨진알·2023년 12월 11일

JavaScript

목록 보기
10/21

다양한 이벤트 알아보기

1. 마우스 버튼 이벤트

MouseEvent.button
0: 마우스 왼쪽 버튼
1: 마우스 휠
2: 마우스 오른쪽 버튼

MouseEvent.type
 * click: 마우스 왼쪽 버튼을 눌렀을 때
 * contextmenu: 마우스 오른쪽 버튼을 눌렀을 때
 * dblclick: 동일한 위치에서 빠르게 두번 click할 때
 * mousedown: 마우스 버튼을 누른 순간
 * mouseup: 마우스 버튼을 눌렀다 뗀 순간

하나의 동작에 여러 이벤트가 발생할 수도 있다. 마우스 왼쪽 버튼을 클릭하여도 click, mousedown, mouseup 3가지 이벤트가 발생할 수 있다.


2. 마우스 이동 이벤트 I

MouseEvent.type
 * mousemove: 마우스 포인터가 이동할 때
 * mouseover: 마우스 포인터가 요소 밖에서 안으로 이동할 때
 * mouseout: 마우스 포인터가 요소 안에서 밖으로 이동할 때 
 
MouseEvent.clientX, clientY
 : 화면에 표시되는 창 기준 마우스 포인터 위치   
MouseEvent.pageX, pageY
 : 웹 문서 전체 기준 마우스 포인터 위치
MouseEvent.offsetX, offsetY
 : 이벤트가 발생한 요소 기준 마우스 포인터 위치
 
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);

2-1. client, page, offset 차이

(1) clientX, clientY

client 프로퍼티는 말 그대로 클라이언트 영역 내에서 마우스의 좌표 정보를 담고있다. 클라이언트 영역이란 이벤트가 발생한 순간에 브라우저가 콘텐츠를 표시할 수 있는 영역을 의미한다.

  • clientX : 브라우저가 표시하는 화면 내에서 마우스의 X좌표 위치를 담고 있다.
  • clientY: 브라우저가 표지사는 화면 내에서 마우스의 Y좌표 위치를 담고 있다.

client 값은 그 순간 보여지는 화면을 기준으로 계산하기 때문에 스크롤 위치와는 무관하게 항상 보여지는 화면의 좌측 상단의 모서리 위치를 (0,0)으로 계산한다.

(2) offsetX, offsetY

offset 프로퍼티는 이벤트가 발생한 target이 기준이 된다.

  • offsetX: 이벤트가 발생한 target 내에서 마우스의 X좌표 위치를 담고 있다.
  • offsetY: 이벤트가 발생한 target 내에서 마우스의 Y좌표 위치를 담고 있다.
    offset 값도 이벤트가 발생한 대상을 기준으로 계산하기 때문에 스크롤 위치와는 무관하게 항상 대상의 좌측 상단의 모서리 위치를 (0,0)으로 계산한다.

(3) pageX, pageY

page 프로퍼티는 전체 문서를 기준으로 마우스 좌표 정보를 담고 있다. 그렇기 때문에 스크롤로 인해서 보이지 않게된 화면의 영역까지 포함해서 측정한다는 점이 앞의 두 프로퍼티와의 차이점이다.

  • pageX: 전체 문서 내에서 마우스의 X좌표 위치를 담고 있다.
  • pageY: 전체 문서 내에서 마우스의 Y좌표 위치를 담고 있다.
    자칫 client 값과 혼동하기 쉬우니 잘 구분해 두는 것이 좋다.


3. 마우스 이동 이벤트 II

MouseEvent.type
 * mousemove: 마우스 포인터가 움직일 때
 * mouseover: 마우스 포인터가 요소 밖에서 안으로 움직일 때
 * mouseout: 마우스 포인터가 요소 안에서 밖으로 움직일 때 
 
MouseEvent.target
: 이벤트가 발생한 요소
MouseEvent.relatedTarget
: 이벤트가 발생하기 직전(또는 직후)에 마우스가 위치해 있던 요소

const box2 = document.querySelector('#box2');

function printEventData(e) {
  console.log('event:', e.type);
  console.log('target:', e.target);
  console.log('relatedTarget:', e.relatedTarget);
  console.log('------------------------------------');
  if (e.target.classList.contains('cell')) {
    e.target.classList.toggle('on');
  }
}

box2.addEventListener('mouseover', printEventData);
box2.addEventListener('mouseout', printEventData);

3-1. mouseenter / mouseleave

mouseentermouseover처럼 마우스 포인터가 요소 바깥에서 안쪽으로 들어갈 때, mouseleavemouseout처럼 마우스 포인터가 요소 안쪽에서 바깥으로 나갈 때 발생한다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="style.css">
    <title>JS with Codeit</title>
  </head>
  <body>
    <div id="box1" class="box">
      <b class="title">mouseover event count: 0</b>
    </div>

    <div id="box2" class="box">
      <b class="title">mouseenter event count: 0</b>
    </div>
    <script>
      const box1 = document.querySelector('#box1');
      const box2 = document.querySelector('#box2');

      let mouseenterCount = 0;
      let mouseoverCount = 0;

      box1.addEventListener('mouseover', function () {
        mouseenterCount++;
        const msg = `mouseover event count: ${mouseenterCount}`;
        box1.lastElementChild.textContent = msg;
      });

      box2.addEventListener('mouseenter', function () {
        mouseoverCount++;
        const msg = `mouseenter event count: ${mouseoverCount}`;
        box2.lastElementChild.textContent = msg;
      });
    </script>
  </body>
</html>
.box {
  display: inline-block;
  width: 200px;
  margin: 20px;
  padding: 60px 35px;
}

#box1 {
  background-color: #B6FFAA;
}

#box2 {
  background-color: #ACFFFC;
}

.title {
  display: inline-block;
  padding: 20px;
  font-size: 18px;
  text-align: center;
  background-color: #FFFFFF;
  border: 1px solid #333333;
}

(1) 버블링이 일어나지 않는다.

mouseentermouseleave는 버블링이 일어나지 않는다. 버블링과 이벤트 위임의 원리로 자식요소인 b.title 부분으로 마우스 커서가 이동할 때도 이벤트가 발생한다. 하지만 mouseenter 타입으로 이벤트 핸들러가 등록된 div#box2 요소에서는 해당 요소 바깥에서 안쪽으로 마우스 커서가 이동할 때만 이벤트 핸들러가 동작하는 모습을 확인할 수 있다.

(2) 자식 요소의 영역을 계산하지 않는다.

mouseentermouseleave는 자식 요소의 영역을 계산하지 않는다. 버블링에 의해 자식 요소로 마우스 커서가 이동할 떄도 이벤트 핸들러가 동작하지만, 자식 요소에서 다시 div#box1 요소로 마우스 커서가 이동할 때도 이벤트 핸들러가 동작한다. mouseover는 자식 요소의 영역을 구분하기 때문이다.

반면, mouseenter는 자식 요소의 영역을 구분하지 않기 때문에 mouseenter 타입으로 이벤트 핸들러가 등록된 div#box2 요소에서는 자식 요소에서 이벤트 핸들러가 동작하지 않는 것뿐만 아니라 자식 요소의 영역에 들어갔다 나올 때도 이벤트 핸들러가 동작하지 않는 모습을 볼 수 있다.


4. 키보드 이벤트

KeyboardEvent.type
 * keydown: 키보드 버튼을 누른 순간
 * keypress: 키보드 버튼을 누른 순간
 * keyup: 키보드 버튼을 눌렀다 뗀 순간
 
KeyboardEvent.key
: 이벤트가 발생한 버튼의 값

KeyboardEvent.code
: 이벤트가 발생한 버튼의 키보드에서 물리적인 위치
const myInput = document.querySelector('#my-input');
const key = document.querySelector('#key');
const code = document.querySelector('#code');

function onkeyEvent(e) {
  const eventBtn = document.querySelector(`#${e.type}`);
  eventBtn.classList.add('check');

  const el = document.querySelector(`#${e.code}`);
  el.classList.add('on');

  if (e.type === 'keyup') {
    el.classList.remove('on');
  } else if (e.type === 'keydown') {
    key.textContent = `key: ${e.key}`;
    code.textContent = `code: ${e.code}`;
  }

  setTimeout(function() {eventBtn.className = 'event'}, 300);
}

myInput.addEventListener('keydown', onkeyEvent);
myInput.addEventListener('keypress', onkeyEvent);
myInput.addEventListener('keyup', onkeyEvent);

5. input 태그 다루기

포커스 이벤트
 * focusin: 요소에 포커스가 되었을 때
 * focusout: 요소에 포커스가 빠져나갈 때
 * focus: 요소에 포커스가 되었을  (버블링 x)
 * blur: 요소에 포커스가 빠져나갈  (버블링 x)

입력 이벤트
 * input: 사용자가 입력을 할 때
 * change: 요소의 값이 변했을 때

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);

6. 스크롤 이벤트

// Scroll 이벤트
let lastScrollY = 0;

function onSroll() {
  const nav = document.querySelector('#nav');
  const toTop = document.querySelector('#to-top');
  const STANDARD = 30;
  
  if (window.scrollY > STANDARD) { // 스크롤이 30px을 넘었을 때
    nav.classList.add('shadow');
    toTop.classList.add('show');
  } else { // 스크롤이 30px을 넘지 않을 때
    nav.classList.remove('shadow');
    toTop.classList.remove('show');
  } 

	if (window.scrollY > lastScrollY) { // 스크롤 방향이 아랫쪽 일 때
    nav.classList.add('lift-up');
  } else { // 스크롤 방향이 윗쪽 일 때
    nav.classList.remove('lift-up');
  }

  lastScrollY = window.scrollY;
}

window.addEventListener('scroll', onSroll);
profile
프론트엔드 지식으로 가득찰 때까지

0개의 댓글