Drag-and-Drop API позволяет переносить различные элементы мышью на определенную позицию на веб-странице. При перемещении элементов у нас есть источник перемещения - элемент, который перемещаем мышью, и цель перемещения - целевая область на веб-странице (другой элемент), на которую надо переместить источник перемещения.
Чтобы определить элемент на веб-странице, который можно перемещать (источник перетаскивания), нужно для этого элемент определить атрибут draggable со значением true. Теоретически в качестве перетаскиваемого элемента может выступать любой элемент веб-страницы. Например:
<div style="width:50px;height:50px; background-color: red;" draggable="true"></div>
По умолчанию элементы не являются перетаскиваемыми.
В качестве цели перетаскиванию может служить произвольный элемент веб-страницы.
После того, как элемент определен как перемещаемый, надо также определить действия, выполняемые при перемещении элемента. Во время операции перетаскивания запускается ряд различных событий:
dragstart: генерируется, когда начинается перетаскивание элемента
drag: генерируется постоянно по мере того, как элемент перетаскивается
dragend: генерируется, когда перетаскивание элемента завершено
dragenter: генерируется, когда элемент входит в границы целевой области
dragover: генерируется постоянно (несколько раз в секунду) по мере того, как элемент перетаскивается над целевой областью
dragleave: генерируется, когда элемент покидает целевую область
drop: генерируется, перетаскиваемый элемент отпускается на целевой области
Обработчики всех выше перечисленных событий перемещения в качестве параметра получают объект типа DragEvent. Этот тип наследует свойства от
MouseEvent и соответственно типа Event
Обработчик события dragstart определяется для перетаскиваемого элемента, а обработчики остальных событий определяются для области, на которую надо переместить элемент. Например:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
<style>
#source { width:50px; height:50px; background-color: red; display: inline-block;}
#target {width: 200px; height: 150px; overflow: hidden; border: #ccc 1px dashed;}
div{margin:5px;}
</style>
</head>
<body>
<div id="source" draggable="true"></div>
<div id="target"></div>
<script>
const source = document.getElementById("source");
source.addEventListener("dragstart", () => console.log("Drag operation started"));
const target = document.getElementById("target");
target.addEventListener("dragover", (event) => {
event.preventDefault();
console.log("Dragover operation");
});
target.addEventListener("drop", () => console.log("Drag operation finished"));
</script>
</body>
</html>
В данном случае перемещаемый элемент имеет идентификатор source, и для него регистрируется обработчик события "dragstart". Оно будет возникать, когда мы захватим элемент указателем мыши и начнем перемещать.
Область, на которую перемещаем элемент, представляет другой элемент с идентификатором target. Для демонстрации для него регистрируем обработчики событий
"dragover" и "drop". Событие "dragover" будет возникать, когда элемент item будет перемещаться поверх элемента target. Чтобы предупредить
генерацию события "drop" во время перемещения, в обработчике этого события вызывается метод event.preventDefault(). Когда мы отпустим элемент item
на элемент target, будет сгенерировано событие "drop".
Однако в выше приведенном примере в реальности перетаскиваемый элемент пока никуда не перемещается. Потому что нам надо установать перемещаемые данные и при завершении перемещения получить их. Например:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
<style>
#source { width:50px; height:50px; background-color: red; display: inline-block;}
#target {width: 200px; height: 150px; overflow: hidden; border: #ccc 1px dashed;}
div{margin:5px;}
</style>
</head>
<body>
<div id="source" draggable="true"></div>
<div id="target"></div>
<script>
let dragged = null; // перемещенные данные
// источник перемещения
const source = document.getElementById("source")
// в обработчике устанавливаем ссылку на перетаскиваемый элемент
source.addEventListener("dragstart", (e) => dragged = e.target);
// целевая область перемещения
const target = document.getElementById("target");
// предупреждаем событие drop
target.addEventListener("dragover", (e) => e.preventDefault());
// копируем перетаскиваемый элемент и помещаем его копию на целевую область
target.addEventListener("drop", (e) => e.target.appendChild(dragged.cloneNode()));
</script>
</body>
</html>
Здесь при начале перетаскивания мы сохраняем перемещаемый объект в переменную dragged
source.addEventListener("dragstart", (e) => dragged = e.target);
При окончании перетаскивания помещаем копию элемента source на элемент target
target.addEventListener("drop", (e) => e.target.appendChild(dragged.cloneNode()));
Таким образом, при перетаскивании на область target будут добавляться копии элемента source:
В качестве альтернативы мы можем выполнить полное перемещение перетаскиваемого элемента:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
<style>
#source { width:50px; height:50px; background-color: red; display: inline-block;}
#target {width: 200px; height: 150px; overflow: hidden; border: #ccc 1px dashed;}
div{margin:5px;}
</style>
</head>
<body>
<div id="target"></div>
<div id="source" draggable="true"></div>
<script>
let dragged = null; // перемещенные данные
// источник перемещения
const source = document.getElementById("source")
// в обработчике устанавливаем ссылку на перетаскиваемый элемент
source.addEventListener("dragstart", (e) => dragged = e.target);
// целевая область перемещения
const target = document.getElementById("target");
// предупреждаем событие drop
target.addEventListener("dragover", (e) => e.preventDefault());
// полностью перемещаем перетаскиваемый элемент на целевую область
target.addEventListener("drop", (e) => {
dragged.parentNode.removeChild(dragged);
e.target.appendChild(dragged);
});
</script>
</body>
</html>
Здесь в обработчике "drop" сначала удаляем перетаскиваемый элемент из родительского контейнера (в данном случае элемента body), а затем добавляем его на целевую область:
target.addEventListener("drop", (e) => {
dragged.parentNode.removeChild(dragged);
e.target.appendChild(dragged);
});