▼ HTML, CSS 문서
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Document</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>
* {
box-sizing: border-box;
}
body {
padding: 50px;
}
.box {
display: flex;
width: 350px;
height: 350px;
}
#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: 0.1;
}
.on {
opacity: 1;
}
#cell-1,
#cell-4 {
color: #ffffff;
background-color: #000000;
}
#cell-2,
#cell-3 {
color: #000000;
background-color: #ffffff;
}
마우스 이동 이벤트 - mousemove
▼ mousemove
box1 id를 가진 요소 위에서 마우스를 움직이면 콘솔에 마우스가 움직이고 있다는 메시지를 출력한다.
const box1 = document.querySelector("#box1");
function onMouseMove() {
console.log("마우스에 움직임이 감지되었습니다.");
}
box1.addEventListener("mousemove", onMouseMove);
요소 위에 마우스가 움직일 때마다 이벤트 핸들러가 동작하는 것을 확인할 수 있다.
이와 같이 마우스가 이동할 때 발생하는 이벤트에는
위치와 관련된 이벤트 객체의 프로퍼티들이 자주 활용된다.
마우스 이벤트 - client, page, offset
대표적으로 client, page, offset 세가지가 많이 활용된다.
이벤트 핸들러의 파라미터에 이벤트 객체(e)를 작성하고
아래와 같이 설정하면 마우스를 움직일 때마다
각 프로퍼티에 해당하는 곳에 X축 Y축 방식으로 위치 정보가 출력된다.
const box1 = document.querySelector("#box1");
function onMouseMove(e) {
// console.log("마우스에 움직임이 감지되었습니다.");
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);
일단 offset 같은 경우에는 이벤트가 발생한 요소 내에서의 포인터 위치를 담고 있다.
다른 값과 비교하면 어느정도 차이가 있는 것을 확인할 수 있는데
client와 page 값을 보면 두 값의 차이가 없다.
또한 스크롤을 한 상태에서 보면 client와 page의 y값이 조금 차이가 나는 것을 볼 수있는데
client는 화면에 표시되는 창을 기준으로 마우스의 위치를 담고 있고
page는 문서 전체를 기준으로 마우스 위치를 담고 있기 때문이다.
좀 더 상세하게 설명하자면..
▼ clientX, clientY
client 프로퍼티는 말 그대로 클라이언트 영역 내에서 마우스의 좌표 정보를 담고있다.
- client area: 이벤트가 발생한 순간에 브라우저가 콘텐츠를 표시할 수 있는 영역을 뜻한다.
- clientX : 브라우저가 표시하는 화면 내에서 마우스의 X좌표 위치를 담고 있다.
- clientY : 브라우저가 표시하는 화면 내에서 마우스의 Y좌표 위치를 담고 있다.
client 값은 그 순간 보여지는 화면을 기준으로 계산하기 때문에 스크롤 위치와는 무관하게
항상 보여지는 화면의 좌측 상단의 모서리 위치를 (0, 0)으로 계산한다.
▼ offsetX, offsetY
offset 프로퍼티는 이벤트가 발생한 target이 기준이 된다.
- offsetX : 이벤트가 발생한 target 내에서 마우스의 X좌표 위치를 담고 있다.
- offsetY : 이벤트가 발생한 target 내에서 마우스의 Y좌표 위치를 담고 있다.
offset 값도 client와 마찬가지로 이벤트가 발생한 대상을 기준으로 계산하기 때문에
스크롤 위치와는 무관하게 항상 대상의 좌측 상단의 모서리 위치를 (0, 0)으로 계산한다.
▼ pageX, pageY
page 프로퍼티는 전체 문서를 기준으로 마우스 좌표 정보를 담고 있다.
그렇기 때문에 스크롤로 인해서 보이지 않게된 화면의 영역까지 포함해서 측정한다는 점이
앞의 두 프로퍼티와의 차이점이다.
- pageX : 전체 문서 내에서 마우스의 X좌표 위치를 담고 있다.
- pageY : 전체 문서 내에서 마우스의 Y좌표 위치를 담고 있다.
※ client 값과 혼동하기 쉬우니 잘 구분하는 것이 좋다.
정리하자면 client, page, offset 이 세 프로퍼티가 각각 어떤 값을 담고 있는지 확인하고
필요한 상황에 따라 적절하게 활용할 수 있다.
예를 들어서 위치 정보를 가지고 특정한 위치에 도달했을 때
어떤 동작이 일어날 수 있도록 설계할 수 있으며
연속적으로 발생한 이벤트끼리의 위치값을 계산하여
x값이 증가하고 y값도 증가했으니 오른쪽 아래 방향으로
마우스가 이동한 방향을 파악하는데 활용할 수 있다.
마우스 이동 이벤트 - mouseover, mouseout
moveover와 mouseout 타입으로 이벤트 객체의 타입 프로퍼티를 출력하는 이벤트핸들러를 등록해 주면
마우스 포인터가 요소 안으로 들어갈 때 mouseover, 밖으로 나올 때 mouseout 이벤트가 발생한다.
const box2 = document.querySelector("#box2");
function printEventData(e) {
console.log(e.type);
}
box2.addEventListener("mouseover", printEventData);
box2.addEventListener("mouseout", printEventData);
이뿐만 아니라 버블링에 의해서 자식 요소 끼리도 (cell-1,2,3,4) 이벤트 핸들러가 동작하는 모습을 확인할 수 있다.
직접 실행해서 자세히 보면 요소끼리 이동할 때 mouseout,mouseover 순서대로
이벤트가 두 번 발생하고 있는 것을 확인할 수 있다.
그러니까 자식 요소(cell-1,2,3,4) 내에서 부요 요소로 나갈 때 (문서 밖이 아니라 다음 요소로 들어갈 때)
moseover가 두 번 발생한다.
그러므로 toggle 메소드를 활용하여 자식 요소의 클래스를 toggle 할때
mouseover에서 클래스가 추가되고 mouseout에서 클래스가 삭제되는 방식으로 동작하게 하여
이벤트 위임을 활용할 수 있다.
function printEventData(e) {
if (e.target.classList.contains("cell")) {
e.target.classList.toggle("on");
}
}
box2.addEventListener("mouseover", printEventData);
box2.addEventListener("mouseout", printEventData);
마우스 이벤트에는 relatedTarget이라는 이벤트 객체의 프로퍼티가 존재하는데
target 프로퍼티는 이벤트가 발생한 요소를 담고 있는 반면에
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("------------------------------------");
}
box2.addEventListener("mouseover", printEventData);
box2.addEventListener("mouseout", printEventData);
결과값을 살펴보면 mouseover 일 때 target이 cell-2고 relatedTarget이 cell-4이므로
cell2에서 4로 마우스가 이동했다는 걸 파악할 수 있다.
mouseout의 경우에는 target이 cell-2이고 relatedTarget이 box2이므로
cell-2에서 box2로 이동했다는 걸 파악할 수 있다.
꼭 이동경로를 이렇게 파악하지 않더라도
이벤트 타입이 mouseover 일 때는 마우스가 이동하기 직전의 요소를 의미하고
mouseout일 경우에는 마우스가 이동한 직후의 요소를 의미하여
편리하게 다룰수 있기 때문에 필요한 상황에 따라 적절하게 사용할 수 있다.
마우스 이동 이벤트 - mouseenter, mouseleave
▼HTML,JavaScript,CSS 문서
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Document</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 src="index.js"></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;
}
const box1 = document.querySelector("#box1");
const box2 = document.querySelector("#box2");
let mouseoverCount = 0;
let mouseenterCount = 0;
box1.addEventListener("mouseover", function () {
mouseoverCount++;
const msg = `mouseover event count: ${mouseoverCount}`;
box1.lastElementChild.textContent = msg;
});
box2.addEventListener("mouseenter", function () {
mouseenterCount++;
const msg = `mouseenter event count: ${mouseenterCount}`;
box2.lastElementChild.textContent = msg;
});
mouseenter는 mouseover처럼 마우스 포인터가 요소 바깥에서 안쪽으로 들어갈 때 발생하고
mouseleave는 mouseout처럼 마우스 포인터가 요소 안쪽에서 바깥으로 나갈 때 발생한다.
▼테스트 해보기
대표적으로 mouseenter와 mouseleave는 버블링이 일어나지 않는다.
이벤트 핸들러 등록된 상태에서 div#box1 요소에서 마우스를 움직여보면
당연히 해당 요소 바깥에서 안쪽으로 마우스 커서가 이동할 때도 이벤트가 발생하지만
버블링과 이벤트 위임의 원리에 따라 자식요소인 b.title 부분으로 마우스 커서가 이동할 때도 이벤트가 발생한다.
하지만 mouseenter 이벤트 핸들러가 등록된 div#box2 요소에는 해당 요소 바깥에서
안쪽으로 마우스 커서가 이동할 때만 이벤트 핸들러가 동작하는 모습을 확인할 수 있다.
또한 mouseenter와 mouseleave는 자식 요소의 영역을 계산하지 않는다.
mouseover 타입으로 이벤트 핸들러가 등록된 div#box1 요소에서 마우스를 움직여보면
버블링에 의해 자식 요소로 마우스 커서가 이동할 때도 이벤트 핸들러가 동작하지만
자식요소에서 다시 div#box1 요소로 마우스 커서가 이동할 때도 이벤트 핸들러가 동작하는 것을 확인할 수 있다.
mouseover는 자식 요소의 영역을 구분하기 때문인 반면..
mouseenter는 자식 요소의 영역을 구분하지 않기 때문에 mouseenter 타입으로 이벤트 핸들러가 등록된
div#box2 요소에는 자식 요소에서 이벤트 핸들러가 동작하지 않는 것 뿐만 아니라
자식 요소의 영역에 들어갔다 나올 때도 이벤트 핸들러가 동작하지 않는것을 확인할 수 있다.
간단하게 정리하면
이벤트가 자식 요소에 영향을 끼치는가? 이 것이 mouseover/mouseout , mouseente/mouseleave 이 둘의
가장 큰 차이라고 할 수있으며
이벤트 핸들러가 자식요소에 영향을 끼치게 하고 싶은 경우에는 mouseover/mouseout을 사용하고
자식 요소에는 영향을 끼치지 않고 해당 요소에만 이벤트 핸들러를 다루고자 한다면 mouseenter/mouseleave를 활용한다.
▼GitHub
'JS' 카테고리의 다른 글
(21) Interactive JavaScript (Event) - input 태그 (0) | 2024.11.15 |
---|---|
(20) Interactive JavaScript (Event) - 키보드 이벤트 (0) | 2024.11.14 |
(18) Interactive JavaScript (Event) - 마우스 버튼 이벤트 (0) | 2024.11.12 |
(17) Interactive JavaScript (Event) - 브라우저의 기본 동작 제어 (0) | 2024.11.11 |
(16) Interactive JavaScript (Event) - 이벤트 위임 (0) | 2024.11.08 |