vue使用拖拽方式创建结构树
短信预约 -IT技能 免费直播动态提醒
本文实例为大家分享了vue使用拖拽方式创建结构树的具体代码,供大家参考,具体内容如下
在页面中拖拽虚线框中的节点,创建向右的结构树,如下图
记录实现思路:
vueTree.vue
<template>
<div class="container">
<div class="node-container">
<div v-for="(item, index) in nodeList"
:key="index"
class="source-node"
draggable="true"
@dragstart="dragStart(item)">
{{ item }}
</div>
</div>
<div class="tree-container"
@dragover="allowDrop"
@drop="handleDrop">
<tree-node v-if="nodeData"
ref="node"
:nodeData="nodeData"
@delete-node="deleteTree" />
</div>
</div>
</template>
<script>
import TreeNode from './treeNode.vue'
import { Node } from './config.js'
export default {
name: 'vue-tree',
components: {
TreeNode
},
// 后代节点无法获取节点数据,即无法独立创建节点,所以将祖先节点的创建节点方法暴露给后代节点
provide () {
return {
createNode: this.createNode
}
},
data () {
return {
nodeList: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
currNode: null,
nodeData: null
}
},
methods: {
// 开始拖拽,获取节点数据
dragStart (item) {
this.currNode = item
},
// 若未生成跟节点,则允许拖拽
allowDrop (event) {
if (!this.nodeData) {
event.preventDefault()
}
},
// 拖拽结束,生成节点
handleDrop () {
if (!this.nodeData) {
this.nodeData = this.createNode()
}
},
createNode () {
let node = new Node(this.currNode)
return node
},
// 根节点删除,删除整个树
deleteTree () {
this.nodeData = null
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 20px;
width: calc(100% - 40px);
height: calc(100% - 40px);
.node-container {
height: 100px;
border: 1px dashed red;
display: flex;
.source-node {
width: 50px;
height: 30px;
background: #fff;
border: 1px solid blue;
text-align: center;
line-height: 30px;
margin: 10px;
cursor: pointer;
}
}
.tree-container {
height: calc(100% - 122px);
margin-top: 20px;
}
}
</style>
config,js
export class Node{
constructor(name){
this.name = name,
this.children = []
}
}
treeNode.vue
<template>
<!--
结构:最外层是node-inner,每个node-inner中有一个node与node-box,node存放当前节点,node-box存放当前节点的全部子节点,当前节点有几个子节点则node-box中就会有几个node-inner,以此循环
<node-inner>
<node></node>
<node-box>
<node-inner>
<node></node>
<node-box>...</node-box>
</node-inner>
<node-inner>
<node></node>
<node-box>...</node-box>
</node-inner>
...
</node-box>
</node-inner>
-->
<div class="node-inner">
<div class="node"
:class="{ 'drag-over-node': isDragover }"
@dragover="dragOver"
@dragleave="dragLeave"
@drop="nodeDrop">
<span class="name">{{nodeData.name}}</span>
<span class="del"
@click="deleteNode">删除</span>
</div>
<div v-show="nodeData.children.length > 0"
class="node-box">
<tree-node v-for="(item,index) in nodeData.children"
:key="index"
:nodeData="item"
@delete-node="deleteChild(index)" />
</div>
</div>
</template>
<script>
export default {
name: 'tree-node',
props: {
nodeData: {
type: Object,
default: () => { }
}
},
// 获取祖先节点传递的数据
inject: ['createNode'],
data () {
return {
isDragover: false
}
},
methods: {
// 节点允许拖拽添加子节点
dragOver (event) {
event.preventDefault()
if (!this.isDragover) {
this.isDragover = true
}
},
dragLeave () {
if (this.isDragover) {
this.isDragover = false
}
},
// 为节点添加子节点
nodeDrop () {
let node = this.createNode()
this.nodeData.children.push(node)
this.isDragover = false
},
// 删除当前节点,本质是交给父级删除子节点
deleteNode () {
this.$emit("delete-node")
},
// 接收删除子节点的指令并执行删除功能
deleteChild (index) {
this.nodeData.children.splice(index, 1)
}
}
}
</script>
<style lang="scss" scoped>
.node {
border: 1px solid orange;
border-radius: 4px;
position: relative;
display: inline-flex;
align-items: center;
justify-content: space-between;
background-color: #fff;
height: 36px;
padding: 0 12px 0 16px;
line-height: 36px;
margin-bottom: 10px;
.name {
font-size: 16px;
margin-right: 12px;
}
.del {
color: red;
font-size: 12px;
cursor: pointer;
}
&.drag-over-node {
box-shadow: 6px 6px 12px rgba(106, 20, 134, 0.15);
}
}
.node-box {
display: inline-flex;
flex-direction: column;
.node-inner {
margin-left: 80px;
// 连接竖条
&:not(:last-child):before {
position: absolute;
left: -70px;
top: 22px;
border: 1px solid orange;
content: "";
width: 8px;
background-color: #fff;
border-bottom-color: #fff;
height: 100%;
border-top-color: #fff;
z-index: 3;
}
// 连接横条
&:after {
left: -61px;
width: 60px;
content: "";
position: absolute;
top: 14px;
height: 8px;
border: 1px solid orange;
content: "";
background-color: #fff;
border-right-color: #fff;
border-left-color: #fff;
z-index: 3;
}
// 最后一个竖条圆滑拐角
&:nth-last-child(2):before {
border-bottom-left-radius: 6px;
border-bottom-color: orange;
}
// 第一个横条拉长
&:first-child:after {
left: -81px;
width: 80px;
z-index: 2;
}
}
}
.node-inner {
position: relative;
}
</style>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341