기록

드래그 앤 드롭 본문

TIL*

드래그 앤 드롭

mnmhbbb 2021. 12. 19. 17:14

* 엘리먼트의 위치를 나타내는 wep api 정리 *

  • Element.getBoundingClientRect()
    엘리먼트의 크기(width, height)와 뷰포트에 상대적인 위치 정보(top, bottom, left, right)를 제공하는 DOMRect 객체를 반환함
    (단, bottom, rigth은 css와는 다른 방식으로 씀.
    css - 오른쪽을 기준으로 엘리먼트까지 떨어져있는 거리
    js - 원점을 기준으로 엘리먼트의 오른쪽까지)

https://developer.mozilla.org/ko/docs/Web/API/Element/getBoundingClientRect

  • offsetX, offsetY
    이벤트 대상 객체에서의 상대적 마우스 좌표 위치
  • clientX, clientY
    현재 보이는 브라우저 기준에서 상대 좌표
  • pageX, pageY
    페이지 기준. 문서 전체 기준
  • screenX, screenY
    모니터 화면 기준

datatransfer

드래그 앤 드롭 할 때 data를 담는 객체

dataTransfer.setData로 전달할 데이터를 담고,
dataTransfer.getData로 데이터를 가져올 수 있다.

드래그 할 객체에는 draggable="true" 속성을 주고,
드래그한 객체를 드롭할 구역에는 dragover, drop 이벤트를 추가해야 한다.

특히 dragover 이벤트에서는 해당 이벤트를 취소하는 기본 처리를 막아야 하기 때문에 preventDefault()를 이벤트리스너에 입력해야 한다.

dragenter (en-US) and dragover (en-US) 두 이벤트 모두에서 preventDefault() 메서드를 호출하는 것은 그 위치에 드랍이 허용되는 것을 나타냅니다. 하지만, 일반적으로 특정한 상황에서만, 예를 들자면 링크가 드래그될 때만 
preventDefault() 메서드를 호출하길 원할 것입니다. 이렇게 하기 위해서는 조건을 확인하여 조건이 충족될 때에만 해당 이벤트를 취소하는 함수를 호출합니다. 조건이 충족되지 않을 경우, 이벤트를 취소하지 않으면 사용자가 마우스 버튼을 놓더라도 드랍은 발생하지 않을 것입니다.
https://developer.mozilla.org/ko/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations
    <div class="container">
      <div class="ball" draggable="true">ball</div>
    </div>
const container = document.querySelector('.container');
const ball = document.querySelector('.ball');

ball.addEventListener('dragstart', function (e) {
  e.dataTransfer.setData('data', this.innerHTML);
  e.dataTransfer.dropEffect = 'copy';
});

container.addEventListener('dragover', function (e) {
  e.preventDefault();
  e.dataTransfer.dropEffect = 'move';
});

container.addEventListener('drop', function (e) {
  let halfWidth = ball.getBoundingClientRect().width;
  let halfHeight = ball.getBoundingClientRect().height;
  alert(e.dataTransfer.getData('data')); // ball
  ball.style.position = 'absolute';
  ball.style.transform = `translate(${e.clientX - halfWidth}px, ${e.clientY - halfHeight}px)`;
});

참조: https://www.zerocho.com/category/HTML&DOM/post/5942c4ed858a010018a8c32f

ball 엘리먼트를 드래그 해서 옮길 때 absolute top, left 값을 주는 방법도 있지만,
성능 최적화를 위해 transform을 사용하였다.

(transform이나 opacity 같은 속성들은 거의 composition만 발생해서 좋고,
width, heigth, top, left 같은 경우는 layout 과정부터 처음부터 시작해야 됨.
그래서 움직이는 변화를 줄 때는 translate가 가장 좋다.)

 


기본 드래그 이벤트에는 한계가 있습니다. 예를 들어, 특정 영역에서 드래그하는 것을 막을 수 없습니다. 수평이나 수직으로만 드래그하는 것도 만들 수 없습니다. 이외에도 드래그 앤 드롭 기능으로 할 수 없는 작업이 많습니다. 모바일 환경에서의 지원도 많이 부족합니다.

기본 드래그 이벤트의 한계를 극복하기 위해 이번 챕터에서 마우스 이벤트를 사용하여 드래그 앤 드롭을 구현하는 방법을 알아보겠습니다.

참조: https://ko.javascript.info/mouse-drag-and-drop

 

<드래그 앤 드롭 알고리즘>

mousedown -> mousemove -> mouseup

1. mousedown에서 움직임이 필요한 요소를 준비함.
이때 기존 요소의 복사본을 만들거나, 해당 요소에 클래스를 추가하는 등 원하는 형태로 작업할 수가 있음

2. 이후 mousemove에서 position: absoulte의 left, top을 변경함

3. mouseup에서는 드래그 앤 드롭 완료와 관련된 모든 작업을 수행함

 

 

'TIL*' 카테고리의 다른 글

blur, focusout  (0) 2021.12.24
이벤트 객체  (0) 2021.12.19
drawer transition 연습  (0) 2021.12.17
JSON, XML  (0) 2021.12.15
React Hook useEffect - Side-effect cleanup  (0) 2021.12.08
Comments