
리플로우가 일어나지 않고 리페인트만 일어나는 transform 속성을 이용할 것이다.
이에 대한 설명은 이 블로그를 참고하자.
우선 수평방향(translateX)만 생각해보자. 움직이는 마우스 포인터의 X좌표는 e.pageX로 알아낼 수 있다. e.pageX - boxLeft를 하면 box의 왼쪽 끝을 기준으로 얼마나 이동했는지를 알 수 있다. 그렇다면 translateX(${e.pageX - boxLeft}px)를 하면 어떻게 될까? 박스의 왼쪽 모서리에 마우스가 고정된 채 움직일 것이다. 하지만 우리는 드래그 시 박스의 중앙에 마우스 포인터가 있는 것이 자연스럽다. 따라서 왼쪽으로 boxWidth/2 만큼 가야하므로 translateX(${e.pageX-boxLeft - boxWidth / 2}px) 이 정답이다. 수직방향(translateY)도 마찬가지이다. 나머지는 다음 소스 코드를 참고하자.
내 코드도 잘 동작하지만, 문제점은 mousemove, mouseup 이벤트를 $box에 추가했다는 것이다. 이렇게 되면 마우스를 빨리 움직였을 때 div를 순간적으로 벗어나 div가 마우스를 따라오지 못하고 멈춰있게 된다. 위 이벤트들을 document에 추가하니 잘 동작함을 확인함.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="../../../myreset.css" />
<link rel="stylesheet" href="index.css" />
<title></title>
<script src="./index.js" defer></script>
</head>
<body>
<div class="box"></div>
</body>
</html>
.box {
margin: 100px auto;
background-color: tomato;
border: 3px solid black;
width: 100px;
height: 100px;
}
const $box = document.querySelector('.box');
$box.addEventListener('mousedown', () => {
$box.addEventListener('mousemove', onMouseMove);
$box.addEventListener('mouseup', () => {
$box.removeEventListener('mousemove', onMouseMove);
});
});
// 이것이 모범 답안
// $box.addEventListener('mousedown', () => {
// document.addEventListener('mousemove', onMouseMove);
// });
// document.addEventListener('mouseup', () => {
// document.removeEventListener('mousemove', onMouseMove);
// });
const boxInfo = $box.getBoundingClientRect();
const boxTop = boxInfo.top;
const boxLeft = boxInfo.left;
const boxWidth = boxInfo.width;
const boxHeight = boxInfo.height;
function onMouseMove(e) {
$box.style.transform = `translate(${e.pageX - boxLeft - boxWidth / 2}px, ${
e.pageY - boxTop - boxHeight / 2
}px)`;
}
mousedown된 시점의 마우스위치와 그 이후에 움직인 마우스 위치의 차이를 이용하여 구현
const $box = document.querySelector('.box');
const initialMousePos = {
x: 0,
y: 0,
};
const offset = { x: 0, y: 0 };
const move = (e) => {
offset.x = e.clientX - initialMousePos.x;
offset.y = e.clientY - initialMousePos.y;
console.log(offset);
$box.style.transform = `translate3d(${offset.x}px, ${offset.y}px,0)`;
};
$box.addEventListener('mousedown', (e) => {
initialMousePos.x = e.clientX - offset.x;
initialMousePos.y = e.clientY - offset.y;
document.addEventListener('mousemove', move);
});
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', move);
});