vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹
本文實(shí)例為大家分享了vue使用拖拽方式創(chuàng)建結(jié)構(gòu)樹的具體代碼,供大家參考,具體內(nèi)容如下
在頁(yè)面中拖拽虛線框中的節(jié)點(diǎn),創(chuàng)建向右的結(jié)構(gòu)樹,如下圖

記錄實(shí)現(xiàn)思路:
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
},
// 后代節(jié)點(diǎn)無(wú)法獲取節(jié)點(diǎn)數(shù)據(jù),即無(wú)法獨(dú)立創(chuàng)建節(jié)點(diǎn),所以將祖先節(jié)點(diǎn)的創(chuàng)建節(jié)點(diǎn)方法暴露給后代節(jié)點(diǎn)
provide () {
return {
createNode: this.createNode
}
},
data () {
return {
nodeList: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
currNode: null,
nodeData: null
}
},
methods: {
// 開始拖拽,獲取節(jié)點(diǎn)數(shù)據(jù)
dragStart (item) {
this.currNode = item
},
// 若未生成跟節(jié)點(diǎn),則允許拖拽
allowDrop (event) {
if (!this.nodeData) {
event.preventDefault()
}
},
// 拖拽結(jié)束,生成節(jié)點(diǎn)
handleDrop () {
if (!this.nodeData) {
this.nodeData = this.createNode()
}
},
createNode () {
let node = new Node(this.currNode)
return node
},
// 根節(jié)點(diǎn)刪除,刪除整個(gè)樹
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>
<!--
結(jié)構(gòu):最外層是node-inner,每個(gè)node-inner中有一個(gè)node與node-box,node存放當(dāng)前節(jié)點(diǎn),node-box存放當(dāng)前節(jié)點(diǎn)的全部子節(jié)點(diǎn),當(dāng)前節(jié)點(diǎn)有幾個(gè)子節(jié)點(diǎn)則node-box中就會(huì)有幾個(gè)node-inner,以此循環(huán)
<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: () => { }
}
},
// 獲取祖先節(jié)點(diǎn)傳遞的數(shù)據(jù)
inject: ['createNode'],
data () {
return {
isDragover: false
}
},
methods: {
// 節(jié)點(diǎn)允許拖拽添加子節(jié)點(diǎn)
dragOver (event) {
event.preventDefault()
if (!this.isDragover) {
this.isDragover = true
}
},
dragLeave () {
if (this.isDragover) {
this.isDragover = false
}
},
// 為節(jié)點(diǎn)添加子節(jié)點(diǎn)
nodeDrop () {
let node = this.createNode()
this.nodeData.children.push(node)
this.isDragover = false
},
// 刪除當(dāng)前節(jié)點(diǎn),本質(zhì)是交給父級(jí)刪除子節(jié)點(diǎn)
deleteNode () {
this.$emit("delete-node")
},
// 接收刪除子節(jié)點(diǎn)的指令并執(zhí)行刪除功能
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;
}
// 最后一個(gè)豎條圓滑拐角
&:nth-last-child(2):before {
border-bottom-left-radius: 6px;
border-bottom-color: orange;
}
// 第一個(gè)橫條拉長(zhǎng)
&:first-child:after {
left: -81px;
width: 80px;
z-index: 2;
}
}
}
.node-inner {
position: relative;
}
</style>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue動(dòng)態(tài)添加class可能帶來(lái)的問(wèn)題解讀(被覆蓋)
文章討論了在使用Vue.js時(shí),通過(guò)動(dòng)態(tài)class修改元素樣式時(shí)可能會(huì)遇到的問(wèn)題,當(dāng)通過(guò)JavaScript動(dòng)態(tài)添加類時(shí),Vue的動(dòng)態(tài)class會(huì)覆蓋掉通過(guò)JavaScript添加的類,導(dǎo)致樣式丟失,這個(gè)問(wèn)題在實(shí)際開發(fā)中可能會(huì)遇到,尤其是在使用第三方框架2024-12-12
一次在vue中使用post進(jìn)行excel表下載的實(shí)戰(zhàn)記錄
最近遇到了需求,覺著有必要給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于一次在vue中使用post進(jìn)行excel表下載的實(shí)戰(zhàn)記錄,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
Vue3+ElementPlus el-date-picker設(shè)置可選時(shí)間范圍的示例代碼
在Vue3中使用Element Plus的el-date-picker組件設(shè)置可選時(shí)間范圍,你可以使用disabled-date屬性,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-07-07
vue實(shí)現(xiàn)消息向上無(wú)縫滾動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)消息向上無(wú)縫滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
vue?實(shí)現(xiàn)彈窗關(guān)閉后刷新效果
這篇文章主要介紹了vue?實(shí)現(xiàn)彈窗關(guān)閉后刷新效果,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
vue-resource攔截器設(shè)置頭信息的實(shí)例
下面小編就為大家?guī)?lái)一篇vue-resource攔截器設(shè)置頭信息的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
詳解vue-cli 腳手架項(xiàng)目-package.json
本篇文章主要介紹了詳解vue-cli 腳手架項(xiàng)目-package.json,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07

