Drag & Drop 를 이용해서 리스트 요소 순서 바꾸기

MDN - HTML 드래그 앤 드롭 APIarrow-up-right

MDN - Drag Operations(실습)arrow-up-right

HTML SPEC - Drag and droparrow-up-right

Codepan examplearrow-up-right

How to Implement Drag and Drop Feature for Your React Componentarrow-up-right

todo list 를 구현했는데, 뭔가 너무 아쉬웠다. 평소에 구현해보고 싶었던 기술중에 Drag & Drop 이 있었는데 todo list 에 적용하기 너무 좋아보여서 시도했다.

인터페이스

DnD 의 인터페이스로는 크게 4가지가 존재한다.

DateEvetDataTranfer 만 알아보자.

DragEvent

이벤트

이벤트 핸들러

설명

dragstart (en-US)

사용자가 요소나 텍스트 블록을 드래그하기 시작했을 때 발생한다. (드래그 시작하기arrow-up-right를 보시오.)

요소나 텍스트 블록을 드래그 할 때 발생한다.

dragend (en-US)

드래그를 끝냈을 때 발생한다. (마우스 버튼을 떼거나 ESC 키를 누를 때) (드래그 끝내기arrow-up-right를 보시오)

dragenter (en-US)

드래그한 요소나 텍스트 블록을 적합한 드롭 대상위에 올라갔을 때 발생한다. (드롭 대상 지정하기arrow-up-right를 보시오.)

dragover (en-US)

요소나 텍스트 블록을 적합한 드롭 대상 위로 지나갈 때 발생한다. (매 수백 밀리초마다 발생한다.)

dragleave (en-US)

드래그하는 요소나 텍스트 블록이 적합한 드롭 대상에서 벗어났을 때 발생한다.

drop (en-US)

요소나 텍스트 블록을 적합한 드롭 대상에 드롭했을 때 발생한다. (드롭하기arrow-up-right를 보시오.)

dragexit

요소가 더 이상 드래그의 직접적인 대상이 아닐 때 발생한다.

Drag 관련 이벤트. 여기서 중요한건 이벤트의 발동 주체가 2가지로 나뉜다는것임.

1. 드래그 요소

마우스로 클릭하고 끌고 다니는 요소

  • drag

  • dragStart

  • dragEnd

2. 드래그 요소와 겹치는 아이템

Define a drop zonearrow-up-right

  • dragEnter

  • dragOver (필수로 구현)

  • dragLeave

  • drop (필수로 구현)

여기서 주목할 건 Drag 요소를 다른 요소 어딘가에 놓으면 그에 대한 이벤트는 drop 이 발생하고 이 drop 을 핸들링 하는 곳이 Drag 된 요소가 아니라 그 요소와 겹치는 아이템이라는 것.

여기서 의문이 생긴다. Drag 된 요소가 아니라 그 요소가 떨어진 곳에서 Drop 이벤트 핸들러를 실행한다면, Drag 된 요소의 정보는 어떻게 넘겨주는거지? 그 의문은 DataFransfer 에서 해결된다.

DataTransfer

https://developer.mozilla.org/ko/docs/Web/API/DataTransferarrow-up-right

get, set 이외에도 여러 메서드, 프로퍼티가 있다. 필요하면 위의 링크로 가서 보자.

실제로 드래그를 이용해서 리스트 요소의 순서를 바꾸는걸 생각해보자.

  1. 요소를 마우스로 잡는다.

    • 마우스로 잡은 요소에서 dragStart 이벤트를 핸들링한다.

  2. 끌고 다닌다.

  3. 원하는 곳에 내려놓는다.

    • 내려놓은 곳의 요소에서 drop 이벤트가 발동된다.

우리는 1번에서 요소에 대한 정보를 어딘가에 저장해야하고, 그 정보를 3번에서 이용해야한다. 이걸 해주는게 DataTransfer다. 사용법은 매우 간단하다. setData 를 통해 데이터를 저장하고, getData 를 이용해서 저장된 정보를 불러온다.

여기를 참고하자arrow-up-right

실제 사용은 아래처럼 하면된다.

localStorage 처럼 get, set 으로 사용하면 된다.

실제 사용하기

todoList 내의 todo 들을 드래그해서 옮기는 코드를 예로 든다. 코드는 여기를 눌러서 확인하자.arrow-up-right

아래의 코드는 미래 재사용을 위해 useDragAndDrop 이라는 커스텀훅으로 만들었다.

1. draggable 속성 넣기

지금까지 내가 만든 웹요소들은 드래그가 모두 불가능했었다. 왜? 바로 draggable 속성을 넣지 않았기 때문이다. 즉 draggable 속성을 넣으면 요소들은 드래깅이 가능해진다.

draggable 속성을 넣음으로써 API 를 사용할 수 있게 된다.

2. onDragStart 핸들러

드래그의 시작을 알려준다. 인터페이스 부분에서 설명했다시피 이 부분에서 옮기는 요소에 대한 정보를 저장해야한다.

코드를 분석해보자면

  1. setIsDragging

    • 현재 todo 가 드래그 하는 중이라는걸 알려주는 state 다.

    • 이 값을 통해 todo 는 자신이 드래깅중인지 또는 아닌지를 알 수 있다.

      • css 핸들링에 사용할 수 있다.

  2. e.dataTransfer.effectedAllowed = move

  3. e.dataTransfer.setData('text/plain', id);

    • 드래그 하는 요소의 정보를 담는다.

3. onDragOver 핸들러

Dropzone

tkdghk

  1. e.preventDefault();

    • 기본으로 발동하는 다른 이벤트들을 막는다. (Touch, pointer events..)

  2. setIsDragOver(true);

    • 현재 요소가 드래그 요소의 아래 깔려있음을 말해준다.

4. onDrop 핸들러

Dropzone

  1. const movingTarget = e.dataTransfer.getData('text/plain');

    • 이전에 저장한 데이터를 가져온다.

  2. callback()

    • todo 요소의 위치를 바꾸는 함수다.

Last updated