[React] drag로 element 옮기기 직접 구현

2023. 10. 3.·🎨 프론트엔드 공부/React & Next

목표

드래그로 엘리먼트 이동시키기

 

결과물

https://codesandbox.io/s/drag-and-drop-ykyxgd?file=/src/Moving.tsx  

 

조건

1. pointer event 사용

- mouse event 와 기능은 거의 동일하나, 모바일 디바이스에서 touch를 지원

- 따라서 mouse event의 상위 호환

 

2. 마우스 커서의 속도에 맞춰서 따라와야 함

- PointerEvent의 movementX, movementY 프로퍼티로 타겟 엘리먼트를 translate시키는 방식은 속도가 느려서 마우스 커서가 쉽게 엘리먼트 바깥으로 나가버리고, 드래그가 끊겨버림..

 

그런데

onMouseMove, onPoinerMove 는 onDragStart에 비해 속도가 느리다...

참고)

https://stackoverflow.com/questions/63862794/custom-draggable-component-too-slow-in-reactjs-when-using-onmousemove

 

draggable로 인한 반투명 드래깅 UI를 주기 싫고, 터치 드래그 효과를 주고 싶었지만, 속도 이슈가 있어서 어쩔 수 없이 drag event 사용...

 

그런데! 전역에 이벤트 핸들러를 등록하면 된다?!

https://velog.io/@bepyan/Drag-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%BD%80%EA%B0%9C%EA%B8%B0

 

1. 클릭 시 전역에 pointermove 이벤트 핸들러(커서 움직임 추적하여 엘리먼트 좌표 업데이트) 등록, pointerup 이벤트 핸들러(등록된 이벤트 핸들러 제거) 등록

 

2. 클릭된 상태에서는 이벤트 핸들러가 등록되어 있으므로 마우스 움직이면 계속 엘리먼트 새 좌표 업데이트됨

 

3. pointerup 이벤트가 실행되면 pointermove 이벤트 핸들러 제거 (1번만 발동되면 됨)

 

코드

import { useState } from "react";

export default function Moving() {
  const [diffPos, setDiffPos] = useState({
    x: 0,
    y: 0
  });

  return (
    <div
      className="window"
      onPointerDown={(e) => {
        const initX = e.clientX;
        const initY = e.clientY;

        const dragMove = (e: PointerEvent) => {
          const newDiffPos = {
            x: diffPos.x + e.clientX - initX,
            y: diffPos.y + e.clientY - initY
          };
          setDiffPos(newDiffPos);
        };

        const dragEnd = (e: PointerEvent) => {
          document.removeEventListener("pointermove", dragMove);
        };

        document.addEventListener("pointermove", dragMove);
        document.addEventListener("pointerup", dragEnd, { once: true });
      }}
      style={{
        transform: `translateX(${diffPos.x}px) translateY(${diffPos.y}px)`
      }}
    >
      <p>hahahahahahahahaha</p>
      <p>hahahahahahahahaha</p>
      <p>hahahahahahahahaha</p>
      <p>hahahahahahahahaha</p>
    </div>
  );
}

 

'🎨 프론트엔드 공부/React & Next' 카테고리의 다른 글
  • 값vs타입, 원시 타입
  • 구조적 타이핑, 구조적 서브타이핑, 덕 타이핑
  • [React] 불필요한 리렌더링 제거하기
  • 비제어 컴포넌트 vs 제어 컴포넌트
지식물원
지식물원
지식이 자라는 식물원!
  • 지식물원
    지식물원
    지식물원
  • 전체
    오늘
    어제
    • 분류 전체보기 (510)
      • 🎨 프론트엔드 공부 (247)
        • JS & TS (86)
        • HTML & CSS (22)
        • React & Next (49)
        • Vue & Nuxt (22)
        • 기타 (68)
      • 🤓 기술 학습 & 공부 기록 (116)
        • Node.js (0)
        • Python (37)
        • 백엔드 (0)
        • 딥러닝 (1)
        • 컴퓨터 일반 (72)
        • 개발 인프라 (6)
      • 👨‍💻 프로젝트 경험 (6)
        • Work (0)
        • Toy (6)
      • ⚙️ 개발 팁 & 노하우 (21)
        • 프론트엔드 (6)
        • 기타 (15)
      • ☕️ 커리어 & 인터뷰 준비 (88)
        • 코딩 테스트 (88)
      • 📰 기술 트렌드 & 생각 정리 (4)
      • 📚 기타 (25)
        • 마케팅 (15)
        • 비개발서적 (10)
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

    • 모바일 접속 시 코드 하이라이팅 깨질 때
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
지식물원
[React] drag로 element 옮기기 직접 구현
상단으로

티스토리툴바