Vue-Tree-Dnd
About The Project
There are plenty of drag-n-drop libraries for Vue. None of them (that I found) support a file/folder-like structure that can create new levels of nesting. I created this library with this spec in mind:
- Support dynamic nesting
- Limit draggable options to what is possible
- Clearly indicate where items will be dropped
- Support collapsing nodes
Getting Started
To get a local copy up and running follow these simple example steps.
Installation
To install, use your favorite package manager and do the equivalent of:
npm install -S vue-tree-dnd@latest
Usage
In Your.vue file, you can import and use the component:
<template>
<VueTreeDnd
:component="MyTreeItemRenderer"
:tree="tree"
@move="moveHandler"
/>
</template>
<script setup>
import { ref } from 'vue'
import VueTreeDnd from 'vue-tree-dnd';
import MyTreeItemRenderer from './my-tree-item.vue'
const tree = ref([
{
id: 1,
name: 'Item 1',
children: [
{
id: 2,
name: 'Item 2',
children: [
{
id: 3,
name: 'Item 3',
children: []
}
]
}
]
}
])
const moveHandler = (event) => {
console.log(event)
}
</script>
API
Tree Data
Your tree data should conform to the following type:
type TreeItem = {
id: number | string
children: TreeItem[]
}
Apart from these properties, you may include any other additional data. This will be passed into the ItemRenderer component.
Move Mutation
type MoveMutation = {
id: number | string
targetId: number | string
position: 'LEFT' | 'RIGHT' | 'FIRST_CHILD' | 'LAST_CHILD'
}
VueTreeDnd
| Prop | Type | Description |
|---|---|---|
| component | Component (Vue) |
Vue component that will render the TreeItem (i.e., ItemRenderer). The component will receive the relevant node in the tree (with its children) as a prop. |
| tree | TreeItem |
The data to be displayed, conforming to the TreeItem type specified above. |
| locked | boolean |
Whether the tree is locked. When true, nodes in the tree will not be draggable. |
| @move | (event: MoveMutation) => void |
Handler for move mutation. Event will fire when node is dropped in a valid location. The syntax of the event data is given in MoveMutation. |
ItemRenderer
| Prop | Type | Description |
|---|---|---|
| item | TreeItem |
The node in the tree that is being rendered. |
| depth | number |
Depth of current node. It is ItemRenderer‘s responsibility to manage indention. |
| expanded | boolean |
Whether the node is expanded (or collapsed). It is ItemRenderer‘s responsibility to manage expand/collapse. |
| setExpanded | (value: boolean) => void |
Callback to control whether the node is collapsed or expanded. To toggle, call setExpanded(!expanded). |
Your ItemRenderer will be draggable but may perform any other actions you wish. For example, you may want to add a button to delete the node. You can do this by adding a delete method to your ItemRenderer component and using provide/inject from the component that imports vue-tree-dnd.
For example:
<template>
<div :style="{ paddingLeft: `${1.5 * depth}rem` }">
<button @click="setExpanded(!expanded)">{{ expanded ? "▼" : "▶" }}</button>
<span>{{ item.name }}</span>
<button @click="delete">X</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
const props = defineProps(['item', 'depth', 'expanded'])
defineEmits(['setExpanded'])
const delete = () => {
const deleteHandler = inject('delete')
deleteHandler(props.item.id)
}
</script>
Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag “enhancement”. Don’t forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
Distributed under the MIT License. See LICENSE.md for more information.
