基于vue3实现从div文本列表中,拖拽复制到另一个div的tree的节点下,并且在这个节点下可以更换排序,不能把节点下的列表拖拽到外面的结点下
时间: 2024-02-01 13:15:26 浏览: 147
vue-tree-list:tree树形结构的Vue组件
5星 · 资源好评率100%
实现这个功能可以分为以下几个步骤:
1. 定义数据结构
首先我们需要定义我们的数据结构,以便于存储我们的节点信息。一个基本的节点包含节点名称、节点 ID、子节点信息等。
```javascript
{
id: 1,
name: '节点1',
children: [
{
id: 2,
name: '子节点1',
children: []
},
{
id: 3,
name: '子节点2',
children: []
}
]
}
```
2. 实现可拖拽的文本列表
我们可以使用 Vue3 中提供的 `draggable` 指令来实现可拖拽的列表。在模板中使用 `v-for` 渲染我们的文本列表,并使用 `v-bind` 绑定 `draggable` 指令,同时绑定事件处理函数。
```html
<div class="text-list">
<div v-for="item in textList"
:key="item.id"
:draggable="true"
@dragstart="dragStart(item)">
{{ item.name }}
</div>
</div>
```
在事件处理函数中,我们需要使用 `event.dataTransfer.setData()` 方法来设置拖拽时携带的数据。
```javascript
methods: {
dragStart(item) {
event.dataTransfer.setData('text/plain', JSON.stringify(item))
}
}
```
3. 实现树形结构
我们可以使用递归的方式来渲染树形结构。在模板中,使用 `v-for` 渲染节点列表。如果当前节点包含子节点,我们递归渲染子节点,直到所有节点都被渲染完成。
```html
<div class="tree">
<div v-for="item in treeData"
:key="item.id"
:class="{ 'tree-node': true, 'tree-node--has-children': item.children.length > 0 }">
<div class="tree-node__name">
{{ item.name }}
</div>
<div class="tree-node__children">
<div v-if="item.children.length > 0">
<Tree :treeData="item.children" @drop="drop"></Tree>
</div>
</div>
</div>
</div>
```
在树形结构中,我们还需要实现拖拽和排序功能。我们可以在每个节点上绑定 `dragover` 和 `drop` 事件处理函数,在事件处理函数中实现对节点的拖拽和排序。
```javascript
methods: {
dragOver(event) {
event.preventDefault()
},
drop(event, target) {
event.preventDefault()
const item = JSON.parse(event.dataTransfer.getData('text/plain'))
if (this.checkValidDrop(item, target)) {
this.$emit('drop', item, target)
}
},
checkValidDrop(item, target) {
// 检查是否为同一个节点或者是否为节点的后代节点
return item.id !== target.id && !this.isDescendant(item, target)
},
isDescendant(parent, child) {
if (parent.children.indexOf(child) !== -1) {
return true
} else {
return parent.children.some((node) => this.isDescendant(node, child))
}
}
}
```
4. 整合拖拽和排序功能
最后,我们将拖拽和排序功能整合起来。在 `drop` 事件处理函数中,我们可以根据拖拽的节点和目标节点的关系来进行不同的操作。如果拖拽的节点是根节点或者目标节点的父节点,则将节点添加到目标节点的子节点列表中。否则,将节点移动到目标节点的前面或后面。
```javascript
methods: {
drop(item, target) {
if (item.id === this.rootId || item.id === target.id || target.children.indexOf(item) !== -1) {
return
}
if (target.parentId === item.parentId) {
const index = target.parent.children.indexOf(target)
const oldIndex = target.parent.children.indexOf(item)
if (index > oldIndex) {
target.parent.children.splice(index + 1, 0, item)
target.parent.children.splice(oldIndex, 1)
} else {
target.parent.children.splice(index, 0, item)
target.parent.children.splice(oldIndex + 1, 1)
}
} else {
target.children.push(item)
item.parent.children.splice(item.parent.children.indexOf(item), 1)
item.parent = target
}
}
}
```
完整代码可以参考以下代码片段:
```html
<template>
<div class="drag-drop-tree">
<div class="text-list">
<div v-for="item in textList"
:key="item.id"
:draggable="true"
@dragstart="dragStart(item)">
{{ item.name }}
</div>
</div>
<div class="tree">
<div v-for="item in treeData"
:key="item.id"
:class="{ 'tree-node': true, 'tree-node--has-children': item.children.length > 0 }"
:data-id="item.id"
@drop="drop(item, $event)"
@dragover="dragOver($event)">
<div class="tree-node__name">
{{ item.name }}
</div>
<div class="tree-node__children">
<div v-if="item.children.length > 0">
<Tree :treeData="item.children" @drop="drop"></Tree>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'DragDropTree',
props: {
textList: {
type: Array,
default: () => []
},
treeData: {
type: Array,
default: () => []
},
rootId: {
type: Number,
default: 0
}
},
methods: {
dragStart(item) {
event.dataTransfer.setData('text/plain', JSON.stringify(item))
},
dragOver(event) {
event.preventDefault()
},
drop(item, event) {
event.preventDefault()
const target = event.target.closest('.tree-node')
if (!target) {
return
}
const targetId = parseInt(target.dataset.id)
if (item.id === this.rootId || item.id === targetId || target.children.indexOf(item) !== -1) {
return
}
if (target.parentId === item.parentId) {
const index = target.parent.children.indexOf(target)
const oldIndex = target.parent.children.indexOf(item)
if (index > oldIndex) {
target.parent.children.splice(index + 1, 0, item)
target.parent.children.splice(oldIndex, 1)
} else {
target.parent.children.splice(index, 0, item)
target.parent.children.splice(oldIndex + 1, 1)
}
} else {
target.children.push(item)
item.parent.children.splice(item.parent.children.indexOf(item), 1)
item.parent = target
}
}
}
}
</script>
```
阅读全文