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); });