drag and drop 기초 (1)

devAnderson·2022년 3월 2일
0

TIL

목록 보기
66/102

웹개발을 하다보면 필연적으로 드래그와 드롭을 사용하게 된다. 해당 옵션에 대해서 명확하게 알고 있어야 사용할 수 있으리라는 생각이 들었으므로 정리를 한다.

이번 내용에서는 기본적인 옵션을 살펴보고, 마우스이벤트 (2)에서는 타입스크립트 + 리엑트를 적용한 드래그 앤 드랍을 구현할 예정이다

🖥 아이디어

dragstart, _dragend 이벤트는 마치 "click" 이벤트처럼 미리 브라우저 내부에 저장되어 있는 이벤트 트리거중 하나이다.
기본적으로 버블링이 가능하며, 이벤트 전처리기 속성으로는 "ondragstart"라는 어트리뷰트로 제공되고 있다.

드래그와 관련된 이벤트는 MouseEvent 클래스로부터 물려받는데, 내부적으로 상당히 비스무레하게 생긴 이벤트 트리거들이 많기 때문에 한번에 정리한다

  1. drag : 드래그가 진행되고 있을 때 연속적으로 발생한다.
  2. dragstart : 드래그 이벤트가 시작되는 순간 일어난다
  3. dragend: 드래그의 이벤트가 끝난직후 발생한다
  4. dragenter : 드래그한 요소가 유효한 드롭영역 대상위에 올라갔을 때 발생한다.

이게 무슨말이냐면, 어떤 요소에 ondragenter이벤트를 감지할 수 있는 리스너 attribute가 존재하는지 안하는지를 의미하는 것이다.

  1. dragleave : 드래그되고있는 요소가 어떤 요소 위를 지나가서 떠나가는 순간 발생한다.
  2. dragover : 드래그하고있는 요소가 이 이벤트 리스너를 가지고 있는 요소 위를 지나가는 경우 밀리세컨드 단위로 실행된다.
  3. drop : 드래그되고 있는 타겟요소가 드롭되는 순간 일어난다.

참고로, dragstart와 dragend는 파일이 타겟요소일 경우는 발생하지 않는다.

드래그 앤 드랍을 구현하기 위해서는 우선 screenX,Y | pageX,Y | clientX,Y | offsetX,Y 를 잘 구분할 수 있어야 한다.

  • screenX,Y = 모니터 스크린에서 좌표위치
  • pageX,Y = html 전체 문서 (뷰포트에 보이지 않는 영역 포함) 에서 좌표
  • clientX,Y = 뷰포트에서 마우스좌표
  • offsetX,Y = 요소를 기준으로 마우스 좌표

또한 getBoundingClientRect() 메서드를 호출하여 해당 요소의 위치좌표를 나타내는 방식을 파악하면 좋다.

실제 적용

우선, 해당 볼을 눌렀을 때 볼 내부에서의 마우스 좌표를 확인할 수 있어야 한다.
이것으을 shiftX, shiftY라고 가정했을 경우,

shiftX를 기준으로 설명하자면 shiftX는

// shiftX 는 해당 요소의 내부 x - 해당 요소의 뷰포트 기준 left만큼 떨어진 위치이다.

let shiftX = event.clientX - ball.getBoundingClientRect().left

그렇다면, 해당 클릭좌표 기준으로 mousedown이 일어났을 때, mouseMove이벤트를 전체 페이지에 걸어주어 요소의 스타일을 지속적으로 움직이게 만들고, 마우스가 올라가면 ("onmouseup") 이벤트 핸들러를 삭제하게 만들면 된다.

function moveAt(pageX, pageY) {
   // 전체 문서기준으로 움직이게 하는 예시이지만, 실제로는 뷰포트기준이 낫다 (innerWidth)
   // 또한, 해당 예시는 left와 top을 움직이게 만들지만 gpu를 이용하는 옵션 (transform)을 사용하는 편이 더 나을것이다.
    e.target.style.left = pageX - shiftX + "px"; 
    e.target.style.top = pageX - shiftX + "px";
}

moveAt(e.pageX, e.pageY);

function onMouseMove(e){
   moveAt(e.pageX, e.pageY)
}

// 전체 문서에서 마우스가 이동하는 경우, 해당 이벤트가 실행되고 요소의 스타일이 바뀌면서 이동한다.
document.addEventListener("mousemove", onMouseMove);

e.target.onmouseup = function(){
    document.removeEventListener("mousemove", onMouseMove);
    e.target.onmouseup = null;
}
profile
자라나라 프론트엔드 개발새싹!

0개의 댓글