A fast and lightweight drag&drop sortable library for Vue.js
A fast and lightweight drag&drop, sortable library for Vue.js with many configuration options covering many d&d scenarios.
Vue Smooth DnD
A fast and lightweight drag&drop, sortable library for Vue.js with many configuration options covering many d&d scenarios.
This library consists wrapper Vue.js components over smooth-dnd library.
Demo
View the demo here:
- https://kutlugsahin.github.io/vue-smooth-dnd
Installation
npm i vue-smooth-dnd
Usage
Vue
<template>
<div>
<div class="simple-page">
<Container @drop="onDrop">
<Draggable v-for="item in items" :key="item.id">
<div class="draggable-item">
{{item.data}}
</div>
</Draggable>
</Container>
</div>
</div>
</template>
<script>
import { Container, Draggable } from "vue-smooth-dnd";
import { applyDrag, generateItems } from "./utils";
export default {
name: "Simple",
components: { Container, Draggable },
data() {
return {
items: generateItems(50, i => ({ id: i, data: "Draggable " + i }))
};
},
methods: {
onDrop(dropResult) {
this.items = applyDrag(this.items, dropResult);
}
}
};
</script>
API: Container
Component that contains the draggable elements or components. Each of its children should be wrapped by Draggable component
Properties
Properties define the visual behaviour of the library:
Property | Type | Default | Description |
---|---|---|---|
:orientation | string | vertical |
|
:behaviour | string | move |
|
:tag | string or NodeDescription | div |
|
:group-name | string | undefined |
|
:lock-axis | string | undefined |
|
:drag-handle-selector | string | undefined |
|
:non-drag-area-selector | string | undefined |
|
:drag-begin-delay | number | 0 (200 for touch devices) |
|
:animation-duration | number | 250 |
|
:auto-scroll-enabled | boolean | true |
|
:drag-class | string | undefined |
|
:drop-class | string | undefined |
|
:remove-on-drop-out | boolean | undefined |
When set true onDrop will be called with a removedIndex if you drop element out of any relevant container |
:drop-placeholder | boolean,object | undefined |
Options for drop placeholder. className, animationDuration, showOnTop |
tag
Tag name or the node definition to render the root element of the Container. Default value is 'div'.
:tag="{value: 'table', props: {class: 'my-table'}}"
tag="table"
possible values
- string : The tag name of the root element to be created
- object : Node definition
- value: string : tag name
- props: data object to define element properties. see https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In-Depth
Lifecycle
The lifecycle of a drag is both described, and can be controlled, by a series of callbacks and events, which are illustrated below for a example containing 3 containers:
Mouse Calls Callback / Event Parameters Notes
down o Initial click
move o Initial drag
|
| get-child-payload() index Function should return payload
|
| 3 x should-accept-drop() srcOptions, payload Fired for all containers
|
| 3 x drag-start dragResult Fired for all containers
|
| drag-enter
v
move o Drag over containers
|
| n x drag-leave Fired as draggable leaves container
| n x drag-enter Fired as draggable enters container
v
up o Finish drag
should-animate-drop() srcOptions, payload Fires once for dropped container
3 x drag-end dragResult Fired for all containers
n x drop dropResult Fired only for droppable containers
Note that should-accept-drop
is fired before every drag-start
, and before every drag-end
, but has been omitted here for clarity.
The dragResult
parameter has the format:
dragResult: {
payload,
isSource,
willAcceptDrop,
}
The dropResult
parameter has the format:
dropResult: {
addedIndex,
removedIndex,
payload,
droppedElement,
}
Note that additional parameters can be passed to callbacks and event handlers by writing an interim handler inline in the markup:
<div v-for="(items, index) in groups"
<Container group-name="column"
:should-accept-drop="(src, payload) => getShouldAcceptDrop(index, src, payload)"
>
...
</Container>
</div>
This can provide handler functions context-sensitive data, such as the loop index or current item.
Callbacks
Callbacks provide additional logic and checks before and during user interaction.
get-child-payload()
The function to be called to get the payload object to be passed onDrop function.
<Container :get-child-payload="getChildPayload">
getChildPayload (index) {
return {
// generate custom payload data here
}
}
Parameters
-
index :
number
: index of the child item
Returns
-
payload :
object
should-accept-drop()
The function to be called by all containers before drag starts to determine the containers to which the drop is possible. Setting this function will override the group-name property and only the return value of this function will be taken into account.
<Container :should-accept-drop="shouldAcceptDrop">
shouldAcceptDrop (sourceContainerOptions, payload) {
return true;
}
Parameters
-
sourceContainerOptions :
object
: options of the source container. (parent container of the dragged item) -
payload :
object
: the payload object retrieved by calling get-child-payload function.
Returns
- boolean : true / false
should-animate-drop()
The function to be called by the target container to which the dragged item will be dropped. Sometimes dragged item's dimensions are not suitable with the target container and dropping animation can be wierd. So it can be disabled by returning false. If not set drop animations are enabled.
<Container :should-animate-drop="shouldAnimateDrop">
shouldAnimateDrop (sourceContainerOptions, payload) {
return false;
}
Parameters
-
sourceContainerOptions :
object
: options of the source container. (parent container of the dragged item) -
payload :
object
: the payload object retrieved by calling get-child-payload function.
Returns
- boolean : true / false
get-ghost-parent()
The function to be called to get the element that the dragged ghost will be appended. Default parent element is the container itself. The ghost element is positioned as 'fixed' and appended to given parent element. But if any anchestor of container has a transform property, ghost element will be positioned relative to that element which breaks the calculations. Thats why if you have any transformed parent element of Containers you should set this property so that it returns any element that has not transformed parent element.
<Container :get-ghost-parent="getGhostParent">
getGhostParent() {
// i.e return document.body;
}
Returns
- Element : Any DOM element that the ghost will be appended in
Events
Events may call user-defined handlers at particular points in the drag-and-drop lifecycle.
@drag-start
Event to be emitted by all containers on drag start.
<Container @drag-start="onDragStart">
onDragStart (dragResult) {
const { isSource, payload, willAcceptDrop } = dragResult
}
Parameters
-
dragResult :
object
-
payload :
object
: the payload object that is returned by get-child-payload. It will be undefined in case get-child-payload is not set. -
isSource :
boolean
: true if it is called by the container which drag starts from otherwise false. -
willAcceptDrop :
boolean
: true if the dragged item can be dropped into the container, otherwise false.
-
payload :
@drag-end
The function to be called by all containers on drag end. Called before drop event.
<Container @drag-end="onDragEnd">
onDragEnd (dragResult) {
const { isSource, payload, willAcceptDrop } = dragResult
}
Parameters
-
dragResult :
object
-
isSource :
boolean
: true if it is called by the container which drag starts from, otherwise false. -
payload :
object
: the payload object that is returned by get-child-payload function. It will be undefined in case get-child-payload is not set. -
willAcceptDrop :
boolean
: true if the dragged item can be dropped into the container, otherwise false.
-
isSource :
@drag-enter
The event to be emitted by the relevant container whenever a dragged item enters its boundaries while dragging.
<Container @drag-enter="onDragEnter">
onDragEnter () {
...
}
@drag-leave
The event to be emitted by the relevant container whenever a dragged item leaves its boundaries while dragging.
<Container @drag-leave="onDragLeave">
onDragLeave () {
...
}
@drop-ready
The function to be called by the container which is being drag over, when the index of possible drop position changed in container. Basically it is called each time the draggables in a container slides for opening a space for dragged item. dropResult is the only parameter passed to the function which contains the following properties.
<Container @drop-ready="onDropReady">
onDropReady(dropResult) {
const { removedIndex, addedIndex, payload, element } = dropResult;
...
}
Parameters
-
dropResult :
object
-
removedIndex :
number
: index of the removed children. Will benull
if no item is removed. -
addedIndex :
number
: index to add droppped item. Will benull
if no item is added. -
payload :
object
: the payload object retrieved by calling getChildPayload function. -
element :
DOMElement
: the DOM element that is moved
-
removedIndex :
@drop
The event to be emitted by any relevant container when drop is over. (After drop animation ends). Source container and any container that could accept drop is considered relevant.
<Container @drop="onDrop">
onDrop (dropResult) {
const { removedIndex, addedIndex, payload, element } = dropResult;
...
}
Parameters
-
dropResult :
object
-
removedIndex :
number
: index of the removed child. Will benull
if no item is removed. -
addedIndex :
number
: index to add dropped item. Will benull
if no item is added. -
payload :
object
: the payload object retrieved by calling get-child-payload function. -
droppedElement :
DOMElement
: the DOM element that is moved
-
removedIndex :
API: Draggable
Wrapper component for Container's children. Every child element should be wrapped with Draggable component.
Properties
tag
Tag name or the node definition to render the root element of the Draggable. Default value is 'div'.
:tag="{value: 'tr', props: {class: 'my-table-row'}}"
tag="tr"
possible values
- string : The tag name of the root element to be created
- object : Node definition
- value: string : tag name
- props: data object to define element properties. see https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In-Depth