본문 바로가기

카테고리 없음

심심해서 혼자서(with MDN)만들어본 드래그 앤 드롭

개요

드래그 앤 드롭이 뭔데?

흔히들 아는 그 기능이 맞다.

바로 이런 기능이다.

마우스로 무언가(예를들면 이미지 또는 엘리먼드)를 끌어 잡아 지정한 이벤트를 발생시키는 기능이다.

생각해보니 나는 드래그 앤 드롭을 라이브러리는 커녕 직접 구현해 본 경험이 없어서 심심한 김에 구글링을 하지 않고 (But Mdn...)을 만들어보았다.

나는 그대르 앤 드롭으로 div 엘리먼트를 옮기는 기능을 만들고 싶었다.

우선은 대충 만들어봤다.

회색 박스안에 있는 엘리먼트를 왼쪽 오른쪽으로 이리저리 옮기는 것이다.


첫 번째 도전...

예로부터 모든 이벤트는 이벤트 리스너로부터 시작한다 하였다... 그것이 바닐라 자바스크립트든 리액트든간에...

그래서 시도해보았다.

짜잔...!

그런데 문제점! 클릭 이벤트는 마우스를 눌렀다 떼는 순간 발생한다. 즉, 쭉 누르고 있어야만하는 드래그에는 적합하지 않다.


두 번째 도전

 

클릭 이벤트가 마우스를 떼는 순간 발생한다면.... 그럼 마우스를 누를 때 이벤트를 발생시키면 되지 않을까?

시도 결과 이벤트를 잘 받긴 한다.. 문제는 잘 받기만 한다는 것.

클릭한 순간 이벤트가 발생되지만, 드래그를하면 div 객체가 딸려오는 것이 아니었다.


세 번째 도전

그렇다면 이벤트의 종류를 한 번 살펴보자. onClick, onAbort, onAnimationStart, onChange....
그러던 중 발견한 onDrag...!
동작을 하지 않았던 또는 예상과 다르게 동작했던 이벤트들과 비슷하게 onDrag이벤트도 동작하지 않았다.
그러나 onDrag는 무언가 달랐다.
느낌이가 와버렸다. 이 녀석이 바로 내가 찾던 그 기능이라고..

But Why....

왜 동작하지 않는 걸까?

그래서 MDN을 압수수색했다.

중요한 부분은 "draggable"!!

바로 시도해보았다.

오예!!!

자 이제 왼쪽 박스에서 오른쪽 박스로 드래그를 하면 오른쪽 박스로 엘리먼트가 이동하는 기능을 구현해보자

  const onDragEnd = (e: React.MouseEvent<HTMLDivElement>, idx: number) => {
    // console.log("dragEnd!!");

    const { clientX } = e;
    const { clientY } = e;
    //현재 위치를 구하고

    if (
      leftDivPosition.left <= clientX &&
      clientX <= leftDivPosition.right &&
      leftDivPosition.top <= clientY &&
      clientY <= leftDivPosition.bottom
    ) {
      //마우스를 놓았을때 leftBox 영역에 잇으면,
      const arr = [...rightValues];
      //rightValues에서 idx번째를 빼내서
      const removedItem = arr.splice(idx, 1);

      setLeftValues((p) => {
        return [...p, ...removedItem];
      }); //빼낸 값을 leftValues에 넣고
      setRightValues(arr);
      //빼낸 나머지 값을 right에 넣는다.
    } else if (
      //오른쪽 박스 영역이라면
      rightDivPosition.left <= clientX &&
      clientX <= rightDivPosition.right &&
      rightDivPosition.top <= clientY &&
      clientY <= rightDivPosition.bottom
    ) {
      const arr = [...leftValues];
      const removedItem = arr.splice(idx, 1);
      setRightValues((p) => [...p, ...removedItem]);
      setLeftValues(arr);
    }
  };

드래그가 끝나면, 끝난 시점의 마우스 위치값을 구하고,
마우스의 위치가 어느 박스에 속해있는지 판단한 다음 값을 다른 곳으로 옮기면 끝난다.
하지만 또 문제점이 발생했다.

(이미지는 그냥 뺐다... 자꾸 이미지가 바뀌니 눈이 아팠다.)

문제는 바로 한박자씩 느리게 이동한다는 것

 

onDragEnd가 마우스를 떼고 얼마간의 시간이 지난 후 동작하는 것으로 보아 onDrag에 해당 로직을 넣으면 되지 않을까...?
하는 꿈을 잠시 꿨습니다...

 

결과는 참담했다. onDrag에 해당 로직을 넣는건 취소...

드래그가 끝나는 시점에 값을 넣고 빼는 동작을 실행시켜야하는 것에는 틀림이없다.
그람 아땋게 마우스를 떼는 순간 값을 넣고 뺄 수가 있을까

이 방법 저 방법을 찾다가 MDN을 천천히 쭉 보게되었다.
그러다 발견한 onDragOver!!

MDN에서 내가 찾고자하는 예제랑 딱 들어맞았다.

 onDragOver={(e) => e.preventDefault()}

바로 사용해보았다.

너무 잘된다...

구글링을 하지않고 (MDN 제외) 처음 시도한 드래그 앤 드롭..

이 기능을 직접 구현하는데 걸린 시간은 3시간 정도 걸린 것 같다.

기능만 본다면 어려워보이지만 실제로 구현해보니 그렇게 어려운 것은 없었다.


그럼 이제 onDrag, onDragStart, onDragover등등의 이벤트 리스너를 알아보자.