Vue uses drag and drop to create a structure tree

Vue uses drag and drop to create a structure tree

This article example shares the specific code of Vue using drag and drop to create a structure tree for your reference. The specific content is as follows

Drag the nodes in the dotted box on the page to create a right-facing structure tree, as shown below.

Record implementation ideas:

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
  },
  // Descendant nodes cannot obtain node data, that is, they cannot create nodes independently, so the node creation method of the ancestor node is exposed to the descendant nodes provide () {
    return {
      createNode: this.createNode
    }
  },
  data () {
    return {
      nodeList: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
      currNode: null,
      nodeData: null
    }
  },
  methods: {
    // Start dragging and get node data dragStart (item) {
      this.currNode = item
    },
    // If the root node is not generated, dragging is allowedallowDrop (event) {
      if (!this.nodeData) {
        event.preventDefault()
      }
    },
    //Drag ends, generate node handleDrop () {
      if (!this.nodeData) {
        this.nodeData = this.createNode()
      }
    },
    createNode () {
      let node = new Node(this.currNode)
      return node
    },
    // Delete the root node and delete the entire tree 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>
  <!-- 
    Structure: The outermost layer is node-inner. Each node-inner contains a node and a node-box. The node stores the current node, and the node-box stores all the child nodes of the current node. If the current node has several child nodes, there will be several node-ins in the node-box, and so on.
        <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">Delete</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: () => { }
    }
  },
  // Get the data passed by the ancestor node inject: ['createNode'],
  data () {
    return {
      isDragover: false
    }
  },
  methods: {
    // The node allows dragging to add child nodes dragOver (event) {
      event.preventDefault()
      if (!this.isDragover) {
        this.isDragover = true
      }
    },
    dragLeave() {
      if (this.isDragover) {
        this.isDragover = false
      }
    },
    // Add child nodes to the node nodeDrop () {
      let node = this.createNode()
      this.nodeData.children.push(node)
      this.isDragover = false
    },
    // Delete the current node, which essentially means handing it over to the parent to delete the child node deleteNode () {
      this.$emit("delete-node")
    },
    // Receive the instruction to delete the child node and execute the delete function 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;
    // Connect the vertical bars&: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;
    }
    // Connect horizontal bar&: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;
    }
    // The last vertical bar has a rounded corner &:nth-last-child(2):before {
      border-bottom-left-radius: 6px;
      border-bottom-color: orange;
    }
    // The first horizontal bar is extended &:first-child:after {
      left: -81px;
      width: 80px;
      z-index: 2;
    }
  }
}
.node-inner {
  position: relative;
}
</style>

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • Detailed explanation of draggable tree table example based on Vue

<<:  Two ways to exit bash in docker container under Linux

>>:  Analysis of the locking mechanism of MySQL database

Recommend

Detailed steps for installing rockerChat in docker and setting up a chat room

Comprehensive Documentation github address https:...

Docker nginx implements one host to deploy multiple sites

The virtual machine I rented from a certain site ...

HTML table markup tutorial (28): cell border color attribute BORDERCOLOR

To beautify the table, you can set different bord...

Summary of data interaction between Docker container and host

Preface When using Docker in a production environ...

Incredible CSS navigation bar underline following effect

The first cutter in China github.com/chokcoco Fir...

Solve the error during connect exception in Docker

When you first start using Docker, you will inevi...

How to write DROP TABLE in different databases

How to write DROP TABLE in different databases 1....

Detailed explanation of TypeScript's basic types

Table of contents Boolean Type Number Types Strin...

CSS3 uses var() and calc() functions to achieve animation effects

Preview knowledge points. Animation Frames Backgr...

Summary of HTML Hack Tags in IE Browser

Copy code The code is as follows: <!--[if !IE]...

How to reset the initial value of the auto-increment column in the MySQL table

How to reset the initial value of the auto-increm...

JavaScript quickly implements calendar effects

This article example shares the specific code of ...

Implementation of crawler Scrapy image created by dockerfile based on alpine

1. Download the alpine image [root@DockerBrian ~]...