이번에는 다른 분의 코드를 거의 그대로 가져왔다. 비록 플젝에는 복붙해 넣었지만 블로그에도 따로 코드를 올려도 되나? 싶었는데 내 프로젝트에 맞게 아주 살짝 변형한 부분이 있어 일단 원본 링크를 걸고 올려보기로 했다. 링크에서는 다양한 드래그들도 많고, codepen을 통해 예제 코드를 바로 실행해볼 수 있다!
https://inpa.tistory.com/entry/드래그-앤-드롭-Drag-Drop-기능#드래그_객체_이동 [Inpa Dev 👨💻:티스토리]
나름 라이브러리 덜 쓰고 만들어보자 했는데(즉 혼자서 다 해보기).. 점점 처음의 포부와는 좀 멀어지는 느낌...
그래도 코드를 살펴본 데 의의를 둬 본다...
touchmove
처럼 모바일 환경을 고려한 부분을 빼고, 내 프로젝트 요소에 적용할 수 있게끔 구조를 조금 수정했다.
// 전체 배경화면
const desktop = document.querySelector('#desktop');
const createDraggable = (dragItem) => {
let active = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;
const dragStart = (e) => {
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
if (e.target === dragItem) active = true;
};
const dragEnd = () => {
initialX = currentX;
initialY = currentY;
active = false;
};
const drag = (e) => {
if (active) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX, currentY, dragItem);
}
};
const setTranslate = (xPos, yPos, el) => {
el.style.transform = 'translate3d(' + xPos + 'px, ' + yPos + 'px, 0)';
};
dragItem.addEventListener('dragstart', dragStart);
desktop.addEventListener('drop', dragEnd);
desktop.addEventListener('dragover', drag);
return dragItem;
};
export { createDraggable };
드래그 대상인 dragItem
에는 dragStart
이벤트에 대한 리스너를 붙여준다. 드래그 대상 요소의 위치를 기준으로 시작 위치를 초기화해야하기 때문이다.
나머지 이벤트들은 desktop
, 즉 화면 요소에 달아준다.
원래 내 프로젝트에서는 별도의 객체나 클래스를 사용하지 않고 있었는데, 드래그 이벤트는 요소별로 그 상태와 위치를 저장하고 있어야 했다. 모든 요소 코드에 중복된 코드를 넣을 수는 없으니 유틸리티로 따로 관리해주면서, 요소별 상태 저장을 해 주기 위해서는 createDraggable
안에 변수와 그를 이용하는 함수들을 하나의 객체 안에 묶어 줘야 했다.
// 명언 요소를 바탕화면에서 클릭했을 때,
const clickQuoteLabel = () => {
...
quoteEl = createlifeQuoteEl(); // 요소 생성
...
addWindowElToDesktop(quoteEl); // 드래그 이벤트 붙여주기
};
호출은 역시 각 요소를 만들 때 이루어진다.
lifeQuoteEl.draggable = true;
참고로 드래그 대상 요소의 draggable
속성을 true
로 해줘야 드래그가 제대로 동작한다!
링크된 포스팅에서 앞서 개념들을 소개하고 있지만 개별 응용 코드에 대해서는 자세한 설명이 없어서 공부할 겸 정리했다.
active
currentX
, currentY
initialX
, initialY
xOffset
, yOffset
dragItem
을 클릭하면 dragStart
함수가 실행된다.
이 함수는 클릭 지점의 위치를 initialX
와 initialY
에 저장하고, xOffset
와 yOffset
을 사용해 이미 이동한 거리를 계산한 뒤 초기 위치에서 뺀다. active
가 true
로 설정되어 있으면 드래그 동작이 활성화된다.
마우스를 움직이면 drag
함수가 실행된다. 이 함수는 currentX
와 currentY
변수를 사용해 마우스의 새 위치를 계산하고, xOffset
와 yOffset
에 새 위치를 저장한 뒤setTranslate
함수를 호출해서 실제 HTML 요소의 위치를 화면에서 이동하게끔 한다.
사용자가 마우스 버튼을 놓으면 dragEnd
함수가 실행된다. 이 함수는 active
를 false
로 설정하여 드래그 동작을 중지하고, '드롭'의 위치를 initialX
와 initialY
에 저장해 다음 드래그 작업을 위한 initialX
, initialY
로 설정한다.
translate3d
CSS의 transform 속성의 일부로, 3D 변환 함수 중 하나이며 주로 요소를 3차원 공간에서 이동시키기 위해 사용된다. 이 함수는 GPU 가속을 사용하여 렌더링되므로 요소의 이동이 더 부드럽게 보일 수 있다.
dragStart
드래그를 시작할 때 발생한다.
dragEnd
드래그를 마치고 마우스 버튼을 놓는 순간 발생한다.
drag
드래그 도중에 발생한다.
dragEnd
와 drop
이 헷갈렸는데 후자는 다른 요소와 상호작용(드래그된 요소를 다른 요소 위에 놓을 때)할 때 사용한다. 여기서는 단독 드래그 이동이어야 하므로 drop
이나 dragover
이벤트는 사용하지 않는다.