드래그 앤 드롭 API는 웹 페이지 내의 요소를 사용자가 자유롭게 드래그할 수 있도록 설정해준다. 웹 페이지 내의 모든 요소는 draggable 속성을 사용하여 드래그될 수 있는 객체(draggable object)로 변환될 수 있다.
✅ dragstart : 사용자가 객체(object)를 드래그하려고 시작할 때 발생함.
✅ dragenter : 마우스가 대상 객체의 위로 처음 진입할 때 발생함.
✅ dragover : 드래그하면서 마우스가 대상 객체의 위에 자리 잡고 있을 때 발생함.
✅ drag : 대상 객체를 드래그하면서 마우스를 움직일 때 발생함.
✅ drop : 드래그가 끝나서 드래그하던 객체를 놓는 장소에 위치한 객체에서 발생함.
✅ dragleave : 드래그가 끝나서 마우스가 대상 객체의 위에서 벗어날 때 발생함.
✅ dragend : 대상 객체를 드래그하다가 마우스 버튼을 놓는 순간 발생함.
드래그를 함으로써 드래그가 시작된 위치와 끝나는 위치의 아이템을 바꾸는 기능을 실현해보자
HTML
<ul class="draggable-list" id="draggable-list"></ul>
CSS
.draggable-list li.over .draggable {
background-color: #eaeaea;
}
JavaScript
자바스크립트 내에서 동적으로 list들을 만들어준다.
const draggable_list = document.getElementById("draggable-list");
const richestPeople = [
"Jeff Bezos",
"Bill Gates",
"Warren Buffett",
"Bernard Arnault",
"Carlos Slim Helu",
"Amancio Ortega",
"Larry Ellision",
"Mark Zuckerberg",
"Michael Bloomberg",
"Larry Page",
];
// Store list items
const listItems = [];
createList();
function createList() {
[...richestPeople]
.map((a) => ({ value: a, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map((a) => a.value)
.forEach((person, index) => {
const listItem = document.createElement("li");
listItem.setAttribute("data-index", index);
listItem.innerHTML = `
<span class="number">${index + 1}</span>
<div class="draggable" draggable="true">
<p class="person-name">${person}</p>
<i class="fas fa-grip-lines"></i>
</div> `;
listItems.push(listItem);
draggable_list.appendChild(listItem);
});
addEventListeners();
}
function dragStart() {
dragStartIndex = this.dataset.index;
}
function dragEnter() {
this.classList.add("over");
}
function dragLeave() {
this.classList.remove("over");
}
function dragOver(e) {
e.preventDefault();
}
function dragDrop() {
this.classList.remove("over");
const dragEndIndex = this.dataset.index;
swapItems(dragStartIndex, dragEndIndex);
}
function swapItems(fromIndex, toIndex) {
const itemOne = listItems[fromIndex].querySelector(".draggable");
const itemTwo = listItems[toIndex].querySelector(".draggable");
listItems[fromIndex].appendChild(itemTwo);
listItems[toIndex].appendChild(itemOne);
}
function addEventListeners() {
const dragListItems = draggable_list.querySelectorAll("li");
dragListItems.forEach((item) => {
item.addEventListener("dragstart", dragStart);
item.addEventListener("dragover", dragOver);
item.addEventListener("drop", dragDrop);
item.addEventListener("dragenter", dragEnter);
item.addEventListener("dragleave", dragLeave);
});
}
드래그가 시작되는 아이템의 인덱스와, 끝나는 인덱스를 인자로 받는 swapItems 함수에서 직접 list내의 드래그 되는 내용을 바꾸어준다.
참고로, dragover 이벤트는 매 millisecond마다 발생하기 때문에 이벤트 기능을 막아줌으로써 drop 이벤트를 실행시킬 수 있게끔 만든다.