Drag N Drop Without Library

오늘은 드래그 앤 드롭을 구현하는 방식을 알아보겠다. 드래그 앤 드롭은 웹에서 많이 사용되는 기능이다. 대부분의 경우에는 라이브러리를 사용하여 구현하지만, 라이브러리 없이 구현하는 방법도 알아보자.

드래그 앤 드롭이란?

드래그 앤 드롭은 마우스를 이용하여 해당하는 요소들을 드래그하여 원하는 위치에 놓는 것을 말한다. 드래그 앤 드롭을 구현하기 위해서는 다양한 이벤트들이 필요하다. 이벤트들은 다음과 같다.

  • dragstart : 드래그가 시작될 때 발생하는 이벤트
  • drop : 드롭이 발생했을 때 발생하는 이벤트
  • dragover : 드래그 중인 요소가 드롭 가능한 영역에 들어왔을 때 발생하는 이벤트
  • dragenter : 드래그 중인 요소가 드롭 가능한 영역에 들어왔을 때 발생하는 이벤트
  • dragleave : 드래그 중인 요소가 드롭 가능한 영역에서 나갔을 때 발생하는 이벤트
  • dragend : 드래그가 끝났을 때 발생하는 이벤트

위와 같은 이벤트들로 드래그 앤 드롭을 구현할 수 있다. 이벤트들을 사용하여 드래그 앤 드롭을 구현해보자.

드래그 앤 드롭 구현

드래그 앤 드롭을 구현하기 위해서는 먼저 드래그가 가능한 요소와 드롭이 가능한 요소가 필요하다. 드래그가 가능한 요소는 draggable 속성을 true 로 설정하면 된다.

<div class="drop">
  <div class="drag" draggable="true"></div>
</div>
<div class="drop">
  <div class="drag" draggable="true"></div>
</div>
<div class="drop">
  <div class="drag" draggable="true"></div>
</div>

먼저 html로 드래그가 가능한 요소를 만들어보았다. 먼저 드래그와 드래그를 마쳤을때 해당하는 요소가 원상 복귀 되는 핸들링하는 함수를 만들어보자.


const drag = document.querySelectorAll('.drag');

drag.forEach((item)=> {
    item.addEventListener('dragstart', dragStart);
    item.addEventListener('dragend', dragEnd);
    });

function dragStart() {
  console.log('drag start', this); // 드래그가 시작되면 드래그 중인 요소를 출력
  this.className += ' hold';
  setTimeout(() => (this.className = 'invisible'), 0);
}

function dragEnd() {
  console.log('drag end', this); // 드래그가 끝나면 드래그 중인 요소를 출력
  this.className = 'drag';
}

먼저 this 키워드를 통해서 지금 함수를 호출하는 요소를 가져올수있다. 이렇게 구현하게 된다면, 개인적으로 별도의 요소를 선택하지 않아도 되어서 코드가 깔끔한 느낌을 준다. 이렇게 구현하게 되면, 드래그가 시작되면 hold 클래스를 추가하고, 0초 뒤에 invisible 클래스를 추가한다. 이렇게 구현하게 되면
, 드래그가 시작되면 hold 클래스가 추가되고, 비동기함수를 통해서 hold 클래스를 제거하고 invisible 클래스를 추가하게 된다. 이렇게 구현하게 되면, 드래그가 시작되면 hold 클래스가 추가되고, 비동기함수를 통해서 hold 클래스를 제거하고 invisible 클래스를 추가하게 된다.

그 다음은 드롭가능한 영역에 대한 핸들링을 해보자. 드롭가능한 영역은 drop 이벤트를 통해서 구현할 수 있다. 그리고 드롭가능한 영역에 dragover 이벤트를 통해서 드래그가 가능한 영역이 드롭가능한 영역에 들어왔을때의 이벤트를 구현할 수 있다. 그리고 다양한 이벤트들을 통해서 더욱 다채로운 이벤트가 구현이 가능하다.

const dropEls = document.querySelectorAll('.drop');

dropEls.forEach((item)=> {
  item.addEventListener('drop', drop);
  item.addEventListener('dragover', dragOver);
  item.addEventListener('dragenter', dragEnter);
  item.addEventListener('dragleave', dragLeave);
})

function dragOver(e) {
  e.preventDefault();
  console.log('drag over');
}

function dragEnter(e) {
  e.preventDefault();
  console.log('drag enter');
}

function dragLeave() {
  console.log('drag leave');
}

function drop() {
  this.append(draggedItem);
}

위와 같이 이벤트를 핸들링 하는 함수를 통해서 Drag N Drop 를 구현할 수 있었다. 하지만 중간에 e.preventDefault() 라는 부분이 있다. 이 부분은 drop 이벤트를 발생하게 했을 때 제대로 작동되기 위해서 필요한 부분이다.
만약 e.preventDefault() 부분이 없다면, drop 이벤트가 발생하지 않을 것 이다. 그렇다면 e.preventDefault() 는 무슨 역할을 하게 되는가?

e.preventDefault()

e.preventDefault() 는 브라우저의 기본 동작을 막는 함수이다. 예를 들어서, a 태그를 클릭했을 때, 해당 링크로 이동하는 기본 동작을 막을 수 있다. 또한 form 태그를 제출했을 때, 해당 form 을 제출하는 기본 동작을 막을 수 있다. 이러한 기본 동작을 막는 함수이다.

해당하는 함수를 통해서 내가 원하지 않는 이벤트를 발생시키지 않는 것을 조절하는 방시도 있다.

저이그냥갓이라이브러리슬가요?

사실 dnd를 라이브러리의 도움이 없다면 구현하기는 사실 상당히 까다롭다. 게다가 성능적인 문제도 있다. 왜냐하면 dragover는 해당하는 요소가 계속 위에 있으면 해당하는 함수를 무한정 호출하기 때문에, 성능적인 문제가 발생할 수 있다. 그래서 이런 문제를 해결하기 위해서 라이브러리를 사용하게 된다.

그래서 대부분은 라이브러리를 사용하는 것이 좋다고 생각된다.

마치며

오늘은 간단하게 dnd를 라이브러리 사용없이 구현하는 방법에 대해서 알아보았습니다. 하지만 라이브러리를 사용하지 않게 된다면 성능적인 이슈가 발생하고, 또 구현하기도 생각외로 까다롭기 때문에 보통은 라이브러리를 사용하는 것이 좋다고 생각합니다.

profile
항상 즐겁고 재밌게!

0개의 댓글