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
dragstartis the first event fired when a drag operation starts on a draggable element
- use
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"
})dropEffectproperty 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
dragoverhandler 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.dropEffectwill be"none"
