다양한 마우스 이벤트 종합정리

Dev_Go·2024년 5월 19일
0

모던 자바스크립트

목록 보기
28/37
post-thumbnail

마우스 버튼이벤트

MouseEvent.button
값 | 내용
:--|:--
0 | 마우스 왼쪽 버튼
1 | 마우스 휠
2 | 마우스 오른쪽 버튼
3 | X1 (일반적으로 브라우저 뒤로 가기 버튼)
4 | X2 (일반적으로 브라우저 앞으로 가기 버튼)

MouseEvent.type
값 | 내용
:--|:--
mousedown | 마우스 버튼을 누르는 순간
mouseup | 마우스 버튼을 눌렀다 떼는 순간
click | 왼쪽 버튼을 클릭한 순간
dblclick | 왼쪽 버튼을 빠르게 두 번 클릭한 순간
contextmenu | 오른쪽 버튼을 클릭한 순간
mousemove | 마우스를 움직이는 순간
mouseover | 마우스 포인터가 요소 위로 올라온 순간
mouseout | 마우스 포인터가 요소에서 벗어나는 순간
mouseenter | 마우스 포인터가 요소 위로 올라온 순간 (버블링이 일어나지 않음)
mouseleave | 마우스 포인터가 요소에서 벗어나는 순간 (버블링이 일어나지 않음)

html

<!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="mouse">
		<div id="btns">
			<div id="btn0" class="btn"></div>
			<div id="btn1" class="btn"></div>
			<div id="btn2" class="btn"></div>
		</div>
	</div>
	<script src="index.js"></script>
	<script src="mouse-event.js"></script>
</body>

</html>

css

#mouse {
	width: 240px;
	height: 390px;
	border: 1px solid #333333;
	border-radius: 150px;
	overflow: hidden;
}

#btns {
	display: flex;
	position: relative;
	width: 100%;
	height: 150px;
	border-bottom: 1px solid #333333;
}

#btn0 {
	width: calc(50% - 1px);
	height: 100%;
	border-right: 1px solid #333333;
}

#btn1 {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	background-color: #FFFFFF;
	width: 40px;
	height: 90px;
	border: 1px solid #333333;
	border-radius: 20px;
}

#btn2 {
	width: 50%;
	height: 100%;
}

.btn {
	display: flex;
	justify-content: center;
	align-items: center;
	font-size: 30px;
	font-weight: 900;
}

.clicked-0 #btn0 {
	background-color: #EB2F2F;
}

.clicked-1 #btn1 {
	background-color: #FFB62E;
}

.clicked-2 #btn2 {
	background-color: #FFFF58;
}

.dblclick #btn0 {
	background-color: #0CB30C;
}

javaScript

let timer = 0;

function printEventType(e) {
	const EVENT_DURATION = 800;
  const eventTime = new Date();

	if (timer === 0) {
    timer = new Date();
	}

	if (eventTime - timer > EVENT_DURATION) {
    console.log('--------------------------');
	}
  
  if (e.target.id !== 'mouse') {
    e.preventDefault();
  }
  
  const btns = document.querySelector(`#btns`);
  const btn = document.querySelector(`#btn${e.button}`);
  btns.classList.add(`clicked-${e.button}`);
  btn.textContent = e.button;
  console.log(`${e.type} 이벤트가 발생했습니다.`);
  
	if (e.type === 'dblclick') {
		btns.className = 'dblclick';
  }
  
  function styleInit() {
    btns.className = '';
    btn.textContent = '';
  }
  
  setTimeout(styleInit, EVENT_DURATION);

  timer = eventTime;
}

document.addEventListener('click', printEventType);
document.addEventListener('contextmenu', printEventType);
document.addEventListener('dblclick', printEventType);
document.addEventListener('mouseup', printEventType);
document.addEventListener('mousedown', printEventType);

마우스에서 어떤 event가 발생했는지 console에서 확인할 수 있는 코드

mousemove, mouseover, mouseout

MouseEvent.type
mousemove: 마우스 포인터가 이동할 때
mouseover: 마우스 포인터가 요소 밖에서 안으로 이동할 때
mouseout: 마우스 포인터가 요소 안에서 밖으로 이동할 때

MouseEvent.target
이벤트가 발생한 요소

MouseEvent.relatedTarget
이벤트가 발생하기 직전(또는 직후)에 마우스가 위치해 있던 요소

html

<!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">
		mousemove
	</div>
	<div id="box2" class="box">
		<b class="title">mouseover / mouseout</b>
		<div id="cell-1" class="cell">cell-1</div>
		<div id="cell-2" class="cell">cell-2</div>
		<div id="cell-3" class="cell">cell-3</div>
		<div id="cell-4" class="cell">cell-4</div>
	</div>
	<script src="index.js"></script>
</body>
</html>

css

* {
	box-sizing: border-box;
}

body {
	padding: 50px;
}

.box {
	display: flex;
	width: 250px;
	height: 250px;
}

#box1 {
	justify-content: center;
	align-items: center;
	margin-bottom: 40px;
	font-size: 35px;
	background-color: #acfffc;
}

#box2 {
	flex-flow: row wrap;
	position: relative;
	padding: 35px;
	background-color: #b6ffaa;
}

#box2 .title {
	position: absolute;
	top: 8px;
	left: 0;
	width: 100%;
	font-size: 18px;
	font-weight: 500;
	text-align: center;
}

.cell {
	width: 50%;
	display: flex;
	justify-content: center;
	align-items: center;
	font-size: 30px;
	font-weight: 900;
	opacity: .1;
}

.on {
	opacity: 1;
}

#cell-1,
#cell-4 {
	color: #FFFFFF;
	background-color: #000000;
}

#cell-2,
#cell-3 {
	color: #000000;
	background-color: #FFFFFF;
}

javascript

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

이동했을 때 어떤 event가 실행되고 target과 relatedTarget이 어떤 요소인지 확인할 수 있는 방법

mouseover와 mouseenter, mouseout과 mouseleave의 차이점

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

mouseentermouseleave는 버블링이 일어나지 않습니다.

위 코드 결과에서 mouseover 타입으로 이벤트 핸들러가 등록된 div#box1요소(왼쪽)에서 마우스를 움직여 보세요.

당연히 해당 요소 바깥에서 안쪽으로 마우스 커서가 이동할 때도 이벤트가 발생하지만, 버블링과 이벤트 위임의 원리로 자식요소인 b.title 부분으로 마우스 커서가 이동할 때도 이벤트가 발생합니다.

하지만 mouseenter 타입으로 이벤트 핸들러가 등록된 div#box2요소(오른쪽)에서는 해당 요소 바깥에서 안쪽으로 마우스 커서가 이동할 때만 이벤트 핸들러가 동작하는 모습을 확인할 수 있습니다.

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

mouseentermouseleave는 자식 요소의 영역을 계산하지 않습니다.

다시 mouseover 타입으로 이벤트 핸들러가 등록된 div#box1요소(왼쪽)에서 마우스를 움직여 봅시다.

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

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

정리

mouseover/mouseout과 비교하면서 mouseenter/mouseleave에 대해 살펴봤는데요.
간단하게 정리하면, 이벤트가 자식 요소에 영향끼치는지가 둘의 가장 큰 차이라고 할 수 있습니다.

그래서 이벤트 핸들러가 자식 요소에까지 영향을 끼치게 하고싶은 경우에는 mouseover/mouseout을, 자식 요소에는 영향을 끼치지 않고 해당 요소에만 이벤트 핸들러를 다루고자 한다면 mouseenter/mouseleave를 활용하면 좋을 것 같습니다.

마우스 이동 이벤트

프로퍼티내용
clientX, clientY마우스 포인터의 브라우저 표시 영역에서의 위치
pageX, pageY마우스 커서의 문서 영역에서의 위치
offsetX, offsetY마우스 포인터의 이벤트 발생한 요소에서의 위치
screenX, screenY마우스 포인터의 모니터 화면 영역에서의 위치

1. clientX, clientY

MouseEvent.clientX, clientY
화면에 표시되는 창 기준 마우스 포인터 위치

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

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

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

2. offsetX, offsetY

MouseEvent.pageX, pageY
웹 문서 전체 기준 마우스 포인터 위치

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

offsetX : 이벤트가 발생한 target 내에서 마우스의 X좌표 위치를 담고 있습니다.
offsetY : 이벤트가 발생한 target 내에서 마우스의 Y좌표 위치를 담고 있습니다.

offset 값도 이벤트가 발생한 대상을 기준으로 계산하기 때문에 스크롤 위치와는 무관하게 항상 대상의 좌측 상단의 모서리 위치를 (0, 0)으로 계산합니다.

3. pageX, pageY

MouseEvent.offsetX, offsetY
이벤트가 발생한 요소 기준 마우스 포인터 위치

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

pageX : 전체 문서 내에서 마우스의 X좌표 위치를 담고 있습니다.
pageY : 전체 문서 내에서 마우스의 Y좌표 위치를 담고 있습니다.

자칫 client 값과 혼동하기 쉬우니 잘 구분해 두시는 것이 좋습니다.

profile
프론트엔드 4년차

0개의 댓글