[POB#31] Assignment 8 : 모두컴퍼니 기업 과제. Drag and Drop 기능 구현 ( VanillaJS )

dongwon·2021년 8월 27일
2

원티드-프리온보딩

목록 보기
22/25
post-thumbnail

Assignment 8 과제를 통해 얻은 지식 정리 글입니다.
과제 레파지토리 : https://github.com/6trillion/Assignmet8-TeamA

Drag and Drop 구현 ( Vanilla JS )

유튜브 영상을 참고해 코드를 분석했습니다.
코드 자료 : https://github.com/WebDevSimplified/Drag-And-Drop

HTML

드래그할 속성들과 속성들을 감싸는 컨테이너로 구성합니다.
draggable 속성을 이용해 드래그가 가능하도록 설정합니다.

<body>
  <div class="container">
    <p class="draggable" draggable>
      1
    </p>
    <p class="draggable" draggable>
      2
    </p>
  </div>
  <div class="container">
    <p class="draggable" draggable>
      3
    </p>
    <p class="draggable" draggable>
      4
    </p>
  </div>
</body>

CSS

CSS를 적용하고, cursor:move로 마우스 커서를 올렸을 때 스타일을 지정해 줍니다.

.draggable {
  cursor: move;
}

JavaScript

사용할 이벤트

  • dragstart : 드래그를 시작하는 순간에 발생하는 이벤트입니다.
  • dragend : 드래그가 끝나는 순간에 발생하는 이벤트입니다.
  • dragover : 드래그를 하는 도중에 발생하는 이벤트입니다.

dragstart, dragend

먼저 draggable, container class를 모두 선택하고 각각에 대해 dragstart, dragend 이벤트를 설정합니다. 각각의 이벤트에 대해 dragging class를 추가, 삭제합니다.

const draggables = document.querySelectorAll(".draggable");
const containers = document.querySelectorAll(".container");

draggables.forEach((draggable) => {
  draggable.addEventListener("dragstart", () => {
    draggable.classList.add("dragging");
  });

  draggable.addEventListener("dragend", () => {
    draggable.classList.remove("dragging");
  });
});

dragover

드래그할 속성들을 감싸고 있는 container에 대해 dragover 이벤트를 설정합니다. 따라서 이 container 안에서 드래그할 때만 이벤트가 발생합니다.

getDragAfterElement 함수를 이용해 드래그한 속성이 지나고 있는 위치의 속성 afterElement을 가져옵니다.

afterElement이 null인 경우는 지나고 있는 속성이 없는 경우, 즉 가장 아래에서 드래그 중임을 의미합니다. 이 경우 appendchild를 이용해 가장 아래에 추가하면서 구현합니다.

afterElement이 존재하는 경우, 어느 속성 어딘가 위에서 드래그하고 있다는 의미입니다. 따라서 inserBefore를 이용해 afterElement 앞에 현재 드래그하고 있는 속성을 추가합니다.

containers.forEach((container) => {
  container.addEventListener("dragover", (e) => {
    e.preventDefault();
    const afterElement = getDragAfterElement(container, e.clientY);
    const draggable = document.querySelector(".dragging");
    if (afterElement == null) {
      container.appendChild(draggable);
    } else {
      container.insertBefore(draggable, afterElement);
    }
  });
});

getDragAfterElement

reducer 메서드y 좌표를 이용해 어느 속성 위를 드래그하고 있는지 알아냅니다.
먼저 드래그 되지 않은 속성들을 배열로 만든 후, 각각의 속성의 getBoundingClientRect를 이용해 topheight 값으로 속성들의 y 값을 구합니다. 여기서는 top - (height / 2)를 이용해 속성의 절반만큼의 위치에서 드래그할 때 위치와 element를 반환합니다.
이 때 reducer 메서드를 이용해 값을 누적시켜 모든 속성들의 y 값을 알 수 있습니다.

function getDragAfterElement(container, y) {
  const draggableElements = [
    ...container.querySelectorAll(".draggable:not(.dragging)"),
  ];

  return draggableElements.reduce(
    (closest, child) => {
      const box = child.getBoundingClientRect();
      const offset = y - box.top - box.height / 2;
      if (offset < 0 && offset > closest.offset) {
        return { offset: offset, element: child };
      } else {
        return closest;
      }
    },
    { offset: Number.NEGATIVE_INFINITY }
  ).element;
}
profile
데이원컴퍼니 프론트엔드 개발자입니다.

0개의 댓글