티스토리 뷰


목차

 

1. 자바스크립트의 드래그 앤 드롭 API

2. draggable 항목의 이벤트

3. drop target에 대한 이벤트

4. dataTransfer 객체를 활용한 자료 전송

5. 예제

6. 드롭 타겟의 이벤트 제어하기


 

 

 

1. 자바스크립트의 드래그 앤 드롭 API


HTML5는 공식적으로 드래그 앤 드롭 스팩을 공개했다. 대부분의 최신 웹 브라우저는 HTML5 스팩을 기반으로 네이티브 드래그 앤 드롭 기능을 구현 할 수 있다.

 

기본적으로 이미지텍스트만 끌 수 있으며 이미지를 끌려면 마우스 버튼을 누른 상태에서 이동하면 된다. 텍스트를 끌려면 일부 텍스트를 하이라이트 해놓고 이미지를 끌 때와 같은 방식으로 끌어다 놓으면 된다.

 

요소를 끌기 위해서는 HTML 태그에 draggable=true 속성을 넣으면 된다. 

<div class="item" draggable="true"></div>

 

 

 

2. draggable 항목의 이벤트


항목을 드래그 하면 다음의 이벤트들이 순서대로 실행된다.

  • dragstart
  • drag
  • dragend

 

 

 

 

3. drop target에 대한 이벤트


올바른 drop 영역으로 항목을 드래그 할 때에는 다음의 이벤트들이 순서대로 실행다.

  • dragenter: 마우스가 대상 객체의 위로 처음 진입할 때 발생함.
  • dragover: 드래그하면서 마우스가 대상 객체의 위에 자리 잡고 있을 때 발생함.
  • dragleave: 드래그가 끝나서 마우스가 대상 객체의 위에서 벗어날 때 발생함.
  • drop: 드래그가 끝나서 드래그하던 객체를 놓는 장소에 위치한 객체에서 발생함.

 

 

 

 

4. dataTransfer 객체를 활용한 자료 전송


드래그 앤 드롭시 자료를 전달하기 위해서는 dataTransfer 객체를 사용한다.

- dataTransfer(): 이벤트의 속성으로 드래그한 항목에서 드롭 타겟으로 자료를 전송할 수 있다.

 

 

dataTransfer 객체는 setData(), getData() 두개의 메소드를 가지고있다..

- setData(): 드래그할 때에 원하는 데이터를 특정한 포멧으로 지정할 수 있다.

dataTransfer.setData(format, data)

여기서 format은 text/plain 이나 text/uri-list가 될 수 있다. data 매개변수에는 드래그 객체에 추가할 문자열 자료를 넣어주면 된다.

 

 

 

- getData(): setData() 메소드로 저장한 드래그 값을 가져온다. 

dataTransfer.getData(format)

format은 text/plain 이나 text/uri-list이고 리턴값은 setData() 메소드로 저장했던 문자열 값 이다.

 

 

 

 

5. 예제


HTML과 CSS 코드는 다음과 같다.

 

 

 

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript - Drag and Drop Demo</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="container">
        <h1>JavaScript - Drag and Drop</h1>
        <div class="drop-targets">
            <div class="box">
                <div class="item" id="item">
                </div>
            </div>
            <div class="box"></div>
            <div class="box"></div>
        </div>
    </div>
    <script src="app.js"></script>
</body>
</html>

 

 

 

 

CSS

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  font-size: 16px;
  background-color: #fff;
  overflow: hidden;
}

h1 {
  color: #323330;
}

.container {
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin: 20px;

}

.drop-targets {
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  margin: 20px 0;
}

.box {
  height: 150px;
  width: 150px;
  border: solid 3px #ccc;
  margin: 10px;

  /* align items in the box */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

}

.drag-over {
  border: dashed 3px red;
}

.item {
  height: 75px;
  width: 75px;
  background-color: #F0DB4F;
}

.hide {
  display: none;
}

 

 

 

 

위 코드를 실행하면 아래와 같은 화면이 나타난다.

 

 

 

노란박스를 드래그 하기 위해서 아래와 같이 draggable="true" 항목을 추가했다.

<div class="item" id="item" draggable="true">

 

 

 

 

추가한 뒤 화면을 보면 노란 박스가 드래그 되는 것을 확인 할 수 있다.

 

 

 

6. 드래그 가능한 항목의 이벤트 제어하기


style.css 파일에 항목을 숨길 수 있도록 .hide 클래스를 추가했다..

.hide {
    display: none;
}

 

 

 

다음으로 app.js 파일에 다음과 같이 코드를 추가했다.

// dom에서 item 항목 가져오기
const item = document.querySelector('.item');

// dragstart 이벤트 추가
item.addEventListener('dragstart', dragStart);

// dragstart 제어
function dragStart(e) {
   console.log('drag starts...');
}

코드 설명:

  • querySelector() 메소드를 사용해 dom에서 드래그 가능한 항목을 가져온다.
  • 가져온 항목에 dragstart 이벤트 핸들러를 추가한다.
  • 이벤트 핸들러로 지정된 dragStart() 함수를 정의한다.

index.html을 새로 열어 노란 박스를 드래그 하면 콘솔(크롬에서는 F12누른 후 console 탭 클릭)에 "drag starts..." 라는 메시지가 뜨는 것을 확인할 수 있다.

 

다음으로 dragStart() 이벤트 핸들 함수에서 드래그 중인 항목의 id를 저장하고 숨기도록 코드를 작성했다.

function dragStart(e) {
    e.dataTransfer.setData('text/plain', e.target.id);
    e.target.classList.add('hide');
}

 

 

 

이 상태로 화면을 갱신하면 노란박스 드래그 시 원래 자리에 있던 노란박스와 드래그 중인 노란박스가 모두 사라지는 것을 확인할 수 있다. 원래 박스는 사라지고 드래그 중인 박스는 보이게 하고싶기 때문에 코드를 수정했다.

function dragStart(e) {
    e.dataTransfer.setData('text/plain', e.target.id);
    setTimeout(() => {
        e.target.classList.add('hide');
    }, 0);
}

 

 

 

 

index.html을 다시 실행해보면 드래그 중이 항목만 보이는 것을 확인할 수 있다.

 

 

 

7. 드롭 타겟의 이벤트 제어하기


앞서 style.css에 .drag-over 클래스를 정의해 드래그 객체가 드롭 타겟 안에 들어왔을 때 점선으로 바뀌도록 하였다.

.drag-over {
    border: dashed 3px red;
}

 

 

 

드롭 타겟이 점선으로 바뀌는 시점은 dragenter와 dragover 이벤트가 실행되었을 때이다. 또한 dragleave, drop 이벤트가 실행되었다면 다시 원래대로 돌아가야하기 때문에 .drag-over 클래스를 드롭 타겟에 추가/제거하는 코드를 넣어 주었다.

function dragEnter(e) {
    e.target.classList.add('drag-over');
}

function dragOver(e) {
    e.target.classList.add('drag-over');
}

function dragLeave(e) {
    e.target.classList.remove('drag-over');
}

function drop(e) {
    e.target.classList.remove('drag-over');
}

 

 

 

 

이후 노란박스를 드래그해서 드롭 타겟 위로 끌어보면 드롭 타겟이 점선으로 바뀌는 것을 확인할 수 있다.

 

 

 

또한 dragenter, dragover 이벤트 핸들러에 event.preventDefault()를 넣어주어야 한다.

function dragEnter(e) {
    e.preventDefault();
    e.target.classList.add('drag-over');
}

function dragOver(e) {
    e.preventDefault();
    e.target.classList.add('drag-over');
}

 

 

위와 같이 실행하지 않는다면 div 항목의 기본값은 유효한 드롭 타겟이 아니기 때문에 drop 이벤트는 실행되지 않는다. 다음으로 드롭 타겟에 드래그 항목을 넣으면 드래그 했던 노란박스가 바로 사라지는 것을 볼 수 있다.

 

이를 해결하기 위해서는 drop 이벤트 핸들러를 정의해야 한다.

  • 먼저 dataTransfer 객체의 getData() 메소드를 통해 드래그 중인 항목의 id를 가져와야 한다.
  • 그 다음 드래그 중인 항목을 드롭 타겟 항목의 자식으로 추가해야한다.
  • 마지막으로 .hide 클래스를 지워 드래그한 항목이 화면에 보이도록 한다.

 

다음은 drop 이벤트 핸들러의 전체 코드이다.

function drop(e) {
    e.target.classList.remove('drag-over');

    // 드래그 중인 항목의 id 가져오기
    const id = e.dataTransfer.getData('text/plain');
    const draggable = document.getElementById(id);

    // 드롭 타겟에 드래그 항목 추가
    e.target.appendChild(draggable);

    // 드래그 했던 항목 화면에 보이기
    draggable.classList.remove('hide');
}

 

 

 

 

이제 다시 실행해 보면 드래그 앤 드롭이 원하는 대로 작동하는 것을 확인할 수 있다.

 

 

 

참고: https://www.javascripttutorial.net/web-apis/javascript-drag-and-drop/