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

jQuery implements all selection and reverse selection operation case

This article shares the specific code of jQuery t...

Complete steps for using Nginx+Tomcat for load balancing under Windows

Preface Today, Prince will talk to you about the ...

How to change the default character set of MySQL to utf8 on MAC

1. Check the character set of the default install...

Vue implements left and right sliding effect example code

Preface The effect problems used in personal actu...

MySQL Basics Quick Start Knowledge Summary (with Mind Map)

Table of contents Preface 1. Basic knowledge of d...

Realize breadcrumb function based on vue-router's matched

This article mainly introduces the breadcrumb fun...

Summary of the data storage structure of the nginx http module

Starting from this section, we will explain the i...

Detailed process of installing logstash in Docker

Edit docker-compose.yml and add the following con...

How to create an Nginx server with Docker

Operating environment: MAC Docker version: Docker...

js realizes the function of clicking to switch cards

This article example shares the specific code of ...

202 Free High Quality XHTML Templates (1)

Here 123WORDPRESS.COM presents the first part of ...

CSS and CSS3 flexible box model to achieve element width (height) adaptation

1. CSS realizes fixed width on the left and adapt...

MySQL optimization connection optimization

In the article MySQL Optimization: Cache Optimiza...

Implementation of built-in modules and custom modules in Node.js

1. Commonjs Commonjs is a custom module in nodejs...

How to use CSS media query aspect-ratio less

CSS media query has a very convenient aspect rati...