I created an example about Javascript Drag-n-Drop APIs at https://hta218.github.io/dnd-keynotes
Below are some interesting key-notes I've learned about the APIs.
Basic concepts
A typical drag operation begins when a user selects a draggable element, drags the element to a dropzone, and then releases the dragged element.
Events:
Event | Fires when… |
---|---|
drag | …a dragged item (element or text selection) is dragged. |
dragend | …a drag operation ends (such as releasing a mouse button or hitting the Esc key) |
dragenter | …a dragged item enters a valid drop target. |
dragexit | …an element is no longer the drag operation's immediate selection target. |
dragleave | …a dragged item leaves a valid drop target. |
dragover | …a dragged item is being dragged over a valid drop target, every few hundred milliseconds. |
dragstart | …the user starts dragging an item. |
drop | …an item is dropped on a valid drop target. |
Keynotes
To make an element draggable, add
draggable="true"
attribute<div draggable="true">This element is draggable</div>
dragstart
dragstart
is the first event fired when a drag operation starts on a draggable elementuse
e.dataTransfer.setData()
method to set any drag's data, this will stay during the drag operation
// The `dragstart` event fires on the `draggable` element dragElem.addEventListener('dragstart', function (e) { // We can set data using `e.dataTransfer.setData` method e.dataTransfer.setData('text/plain', e.target.id) // Use e.dataTransfer.setDragImage() to change the drag image // e.dataTransfer.setDragImage(img | element, xOffset, yOffset) })
- If you don't want the translucent image generated from the drag target during drag, use
e.dataTransfer.setDragImage()
to change it
The dropEffect
- The dropEffect property is used to control the feedback the user is given during a drag-and-drop operation
dragElem.addEventListener('dragstart', function (e) { e.dataTransfer.setData('text/plain', e.target.id) // The `move` value works on window, not on macOS - It might be the problem of browser along with OS e.dataTransfer.dropEffect = 'move' // or "copy" })
dropEffect
property could be:move
: dragged data will be moved to the dropzone.copy
: dragged data will be copied to the dropzone.- ..
The dropzone
To make an element becomes a dropzone, it must have both dragover and drop event handler.
Remember to call e.preventDefault() in
dragover
handler or the browser won't let you drop anything inside
dropzone.addEventListener('dragover', function handleDragOver(e) { // The `dropzone` element must have both `dragover` and `drop` event // Remember to preventDefault the behavior or the browser or it will not let you drop anything inside e.preventDefault() e.dataTransfer.dropEffect = 'move' }) dropzone.addEventListener('drop', function handleDrop(e) { // NOTE: there must be a handler for dragover to use drop event e.preventDefault() // Use `e.dataTransfer.getData` method to retrieve drag's data and process them let data = e.dataTransfer.getData('text/plain') // NOTE: Keep mind that we can only use the `dataTransfer.getData()` in the `drop-handler` // `getData()` will return empty string inside handle dragover or dragenter })
- Keep mind that we can only use the
dataTransfer.getData()
in thedrop-handler
(it will return empty string inside dragover or dragenter handler)
dragend
- The dragend event fires after a drag operation finished regardless of whether the drag completed or was canceled
// The `dragend` event fired on the `draggable` element (not the dropzone element) dragElem.addEventListener('dragend', function handleDragEnd(e) { // We can check if the drag was successful or not by checking the ʻe.dataTransfer.dropEffect` value let dropEffect = e.dataTransfer.dropEffect // If that fails, the value of `e.dataTransfer.dropEffect` will be "none" })
- If the drag operation failed, the value of
e.dataTransfer.dropEffect
will be"none"