Drag and Drop 구현하기

바다·2023년 8월 28일
0

javascript

목록 보기
3/4
post-thumbnail

drag and drop 기능을 있는 프로젝트들을 만들면서 알게된 drag and drop 을 구현하는 방법 대해 정리해보려 한다.

1. 구현 목표,계획

<ul class="list">
  {list.map((e,i)=> <li class="item" key={i}>{e.data}</li>)}
</ul>

item이 요소로 들어 있는 배열 형식의 list가 존재하고, 드래그 앤 드롭의 대상은 item 이고, item 을 드래그하면 해당 item이 지나가는 영역안에 있는 다른 item에 이를 표시하기로 하고 item을 원하는 위치에 드롭할 경우 위치에 맞추어 list을 변경하는 것을 구현하고자 했다.

필요한 기능은 다음과 같다.

  1. 드래그가 시작될 때, 드래그 대상인 item (이하 target)의 스타일을 변경하는 기능
  2. 드래그시 target을 복사한 요소가 나타나고 마우스나 터치의 움직임에 따라 복사한 요소의 위치를 변경하는 기능
  3. target의 영역과 곁치는 다른 item이 있을 경우, 이를 화면에서 표시하기 위해 곁치는 item (이하 dragover item)의 스타일을 변경하는 기능
  4. target을 드롭해서 list를 변경하는 기능
  • item 지칭 정리
지칭설명
target드래그 대상인 item
drag item드래그 대상인 item을 복사한 요소로, 드래그 시 마우스나 터치를 따라다님
dragover itemdrag item의 영역과 곁치는 item으로 드롭 시 dragover item의 위치에 target 위치하게 됨

2. 구현

1) event

드래그 앤 드롭은 mouse event, drag event, touch event를 통해 구현할 수 있다.

HTML은 요소의 드래그 가능 여부를 의미하는 draggable 속성과 사용자가 드래그하는 동안 일어나는 drag event를 지원하고 이들을 통해서 드래그 앤 드롭 기능을 구현할 수 있다.

문제는 브라우저별로 기능 지원 여부를 확인할 수 있는 사이트에서 모바일 브라우저에서 draggable 속성과 drag event를 지원한다고 하지만 모바일 브라우저에서는 작동이 되지 않았어서 모바일 브라우저에서도 드래그 앤 드롭 기능을 구현하기를 원한다면 touch event를 통해 구현해야했다.

draggable 속성과 drag event를 사용하면, 드래그 시 target을 복사한 요소(이하 drag item)가 생성되어서 마우스를 따라다니다가 drop 시에 사라지게 된다.
그러나 mouse event, touch event를 이러한 기능이 없기 때문에 드래그 시 drag item 요소가 필요하다면 드래그 시 해당 요소가 나타나도록 추가로 구현해주어햐한다.

이벤트동작하는 브라우저drag item 자동 생성
drago
mousex
touch모바일x

2) drag event

drag event는 item에서 설정해주었고, item을 특정 지역에 드롭하기 위해서는 item에는 꼭 dragover와 drop 이벤트를 설정해주어야한다.

이벤트기능
dragstartitem을 drag의 대상으로 설정
dragenditem을 drag 대상에서 제외함
dragentertarget이 해당 item의 영역에 들어왔을 때 해당 item을 dragover item으로 설정
dragleavetarget의 영역에서 벗어나서 해당 item을 dragover item에서 제외함
dragoverevent.preventDefault()
drop드롭된 위치에 맞게 list를 변경

3) mouse event , touch event

list에는 별다른 event 설정이 없었던 drag event와 달리 mouse,touch event는 list에도 event를 설정해주어야 하고, 모바일 브라우저에서 드래그 작동여부를 나타내는 상태(이하 mobileDrag)도 필요하다.

a. item

item의 event들은 마우스 동작이나 터치 동작이 드래그를 위한 동작인지를 판단하는데 사용된다. 즉, mousedown,touchstart 후에 일정 시간이 경과해야 이를 드래그를 위한 동작으로 판단하고 만약 일정 시간이 경과하기 전에 mouseup,touchend가 진행이 된다면 이는 드래그를 위한 동작이 아니라고 판단한다.

  • touch event 기준

    이벤트기능
    touchstartmobileDrag === false 일때, 일정 시간이 지나면 mobileDrag를 true로 변경하는 setTimeout 진행
    touchendtouchstart에서 진행한 setTimeout을 지우는 clearTimeout을 진행

b. list

list에서는 drag item을 화면에 보여주고 마우스나 터치의 위치에 따라 해당 요소의 위치를 변경하고, mouseup이나 touchend가 일어날 때 드롭에 따른 list의 상태를 변경해주는 동작들이 이루어진다.

  • touch event 기준

    이벤트기능
    touchmove- drag item 위치 변경
    - drag item의 영역과 곁치는 item을 dragover item으로 설정하고 그렇지 않은 item 중 dragover item이였던 item을 dragover item에서 제외
    touchend터치가 끝났을때, dragover item의 위치에 target을 넣어서 list를 변경하고 드래그를 위한 설정들을 원래대로 복원
  • dragover item 설정 및 제외
    dragover item을 설정 하거나 제외하기 위해서 모든 item의 위치와 drag item의 위치를 비교해야하고 여기서 사용된 위치는 item의 부모인 list 요소를 기준으로 한 item의 상대적인 위치이다.

    const listElTop = listEl.getClientRects()[0].top;
         const item = [...document.querySelectorAll(".list .item")].map(
           (e, i) => ({ element: e, y: e.getClientRects()[0].top - listElTop })
         );

    drag and drop 구현한 프로젝트 보러가기

    🖱️sortable list package

  • github 바로가기

  • npm 바로가기

    💽 music-playlist

  • github 바로가기

  • 프로젝트 사이트 바로가기

profile
🐣프론트 개발 공부 중 (우테코 6기)

0개의 댓글