부자 되기 위한 블로그, 머니킹

Description

드래그 이벤트가 발생하면 기본적인 이벤트로 발생한 요소에 대해 마우스 포인터 쪽에 드래그 이미지가 표시된다. 이 때 event 객체 하위에 setDragImage를 통해 마우스 포인터에 잡히는 드래그 이미지를 표시할 수 있다. 이런메서드들을 보면 웹개발의 역사가 길다보니 왠만한 이벤트 처리에 대한 것들은 모두 구현되어 있는 것 같다.


Diagram

만약 순수 js 로만 구현한다면 drag시 발생하는 모든 이벤트에 대해 setDragImage를 설정해야 해당 이미지가 잘 적용되는 것 같았다 (이 부분은 정확하지는 않다) 존재하는 drag event는 다음과 같다 (MDN 참조)


var dragged;

/* 드래그 가능한 대상에서 이벤트 발생 */
document.addEventListener("drag", function(event) {

}, false);

document.addEventListener("dragstart", function(event) {
  // 드래그한 요소에 대한 참조 변수
  dragged = event.target;
  // 요소를 반투명하게 함
  event.target.style.opacity = .5;
}, false);

document.addEventListener("dragend", function(event) {
  // 투명도를 리셋
  event.target.style.opacity = "";
}, false);

/* 드롭 대상에서 이벤트 발생 */
document.addEventListener("dragover", function(event) {
  // 드롭을 허용하도록 prevetDefault() 호출
  event.preventDefault();
}, false);

document.addEventListener("dragenter", function(event) {
  // 요소를 드롭하려는 대상 위로 드래그했을 때 대상의 배경색 변경
  if (event.target.className == "dropzone") {
    event.target.style.background = "purple";
  }

}, false);

document.addEventListener("dragleave", function(event) {
  // 요소를 드래그하여 드롭하려던 대상으로부터 벗어났을 때 배경색 리셋
  if (event.target.className == "dropzone") {
    event.target.style.background = "";
  }

}, false);

document.addEventListener("drop", function(event) {
  // 기본 액션을 막음 (링크 열기같은 것들)
  event.preventDefault();
  // 드래그한 요소를 드롭 대상으로 이동
  if (event.target.className == "dropzone") {
    event.target.style.background = "";
    dragged.parentNode.removeChild( dragged );
    event.target.appendChild( dragged );
  }
}, false);




Event DataTransfer setDragImage

드래그가 발생하면 반투명한 이미지가 생성되는데 이는 마우스 포인터를 따라간다. 사실 setDragImage를 활용해야 하는 순간은 정해져 있다. 드래그시 이미지의 배경을 없애고 싶거나 특정 default를 드래그 할 때 기본적인 이미지를 적용하고 싶을 때이다.


Syntax

setDragImage(imgElement, xOffset, yOffset)

첫 인자로 image element를 삽입한다. 나같은 경우에는 document.createElement를 통해 새로운 image element를 만들고 이를 div로 감싼 후에 넣어주는 편이다. xOffset과 yOffset 같은 경우에는 보통 0,0으로 설정한다.




구현 방법

내가 실제 프로젝트를 진행하면서 구현했던 setDragImage 코드이다.


function drag_image_set(e) {

        drag_div.style.width="32px";
        drag_div.style.height="32px";

        console.warn("src_drag_icon : ", src_drag_icon);
        drag_icon.src = src_drag_icon;

        drag_icon.style.width="32px";
        drag_icon.style.height="32px";

        document.querySelector("body").appendChild(drag_div)

        drag_div.appendChild(drag_icon);

        e.dataTransfer.setDragImage(drag_div, e.offsetX, e.offsetY);
    }

나 같은 경우에는 drag 이벤트가 list의 순서를 바꾸는데 구현되어 있다. 따라서 srouce div 부분에서 아이콘 부분만 드래그 이미지로 설정하고 싶어 위와 같이 구현하였다. img element를 만들고 나서 div로 감싼후에 등록시킨 것을 알 수 있다.


Array.from(items).forEach((item, idx) => {
        item.addEventListener('dragstart', e => handle_drag_start(e, idx));
        item.addEventListener('dragover', e => handle_drag_over(e, idx));
        item.addEventListener('dragenter',e => handle_drag_enter(e, idx));
        item.addEventListener('dragleave', e => handle_drag_leave(e,idx));
        item.addEventListener('dragend', e=> handle_drag_end(e,idx));
        item.addEventListener('drop', e=> handle_drop(e,idx));
    });

위와 같이 등록한 이벤트 함수에 drag_image_set 함수를 삽입해주었다. mdn의 량이 너무 방대해서 event 하위 메소드에 대해 잘 공부하지 못했는데 이번 기회에 좀 더 연구해봐야겠다.