Assignment 8 과제를 통해 얻은 지식 정리 글입니다.
과제 레파지토리 : https://github.com/6trillion/Assignmet8-TeamA
유튜브 영상을 참고해 코드를 분석했습니다.
코드 자료 : https://github.com/WebDevSimplified/Drag-And-Drop
드래그
할 속성들과 속성들을 감싸는 컨테이너로 구성합니다.
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를 적용하고, cursor:move로 마우스 커서를 올렸을 때 스타일을 지정해 줍니다.
.draggable {
cursor: move;
}
드래그
를 시작하는 순간에 발생하는 이벤트입니다.드래그
가 끝나는 순간에 발생하는 이벤트입니다.드래그
를 하는 도중에 발생하는 이벤트입니다.먼저 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");
});
});
드래그
할 속성들을 감싸고 있는 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);
}
});
});
reducer 메서드와 y 좌표를 이용해 어느 속성 위를 드래그
하고 있는지 알아냅니다.
먼저 드래그
되지 않은 속성들을 배열로 만든 후, 각각의 속성의 getBoundingClientRect를 이용해 top
과 height
값으로 속성들의 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;
}