Maison  >  Article  >  interface Web  >  Comment utiliser Vue pour créer des organigrammes ?

Comment utiliser Vue pour créer des organigrammes ?

WBOY
WBOYoriginal
2023-06-25 09:16:433864parcourir

Avec le développement d'Internet, de plus en plus d'applications nécessitent la production d'organigrammes, tels que des organigrammes de flux de travail, des schémas de circuits, etc. En tant que framework frontal très populaire, Vue.js offre une excellente interactivité et maintenabilité, il est donc largement utilisé pour créer des applications d'organigrammes complexes.

Cet article présentera comment utiliser Vue pour implémenter la production d'organigrammes, y compris les étapes suivantes :

  1. Installer les dépendances nécessaires
  2. Écrire la structure de base des composants
  3. Implémenter la fonction glisser-déposer
  4. Implémenter la ligne de connexion
  5. implémenter l'édition des nœuds
  6. Export Flowchart
  7. Installation des dépendances nécessaires

Tout d'abord, nous devons installer la bibliothèque vue-draggable-resizing, qui est un plug-in Vue très facile à utiliser qui peut réaliser le glisser et fonctions de zoom des éléments. Nous pouvons utiliser l'installation npm :

npm install vue-draggable-resizable --save
  1. Écrivez la structure de base des composants

Nous devons utiliser les composants Vue pour implémenter l'édition d'organigrammes. Nous devons créer un composant FlowChart qui contient tous les éléments de l'organigramme. Chaque nœud est un composant Node qui représente une étape dans l'organigramme. Les lignes de connexion sont des composants de connexion utilisés pour connecter différents nœuds.

Tout d'abord, nous devons créer un composant FlowChart abstrait dans le fichier FlowChart.vue pour contenir tous les nœuds et lignes de connexion :

<template>
  <div class="flowchart">
    <div class="nodes">
      <!-- 组件插槽,用于插入节点 -->
      <slot name="nodes"></slot>
    </div>
    <svg class="connections">
      <!-- 组件插槽,用于插入连接线 -->
      <slot name="connections"></slot>
    </svg>
  </div>
</template>

<script>
export default {
  name: 'FlowChart'
}
</script>

Nous plaçons les nœuds et les lignes de connexion dans les deux emplacements du composant FlowChart respectivement.

Ensuite, nous devons créer des composants Node et Connection pour représenter les nœuds et les lignes de connexion de l'organigramme :

Node.vue :

<template>
  <draggable-resizable :w="width" :h="height" :x="x" :y="y">
    <div class="node">
      <!-- 节点的内容 -->
      <div class="node-content">
        <slot></slot>
      </div>
    </div>
  </draggable-resizable>
</template>

<script>
import VueDraggableResizable from 'vue-draggable-resizable'

export default {
  name: 'Node',
  components: {
    VueDraggableResizable
  },
  props: {
    width: {
      type: Number,
      default: 100
    },
    height: {
      type: Number,
      default: 50
    },
    x: {
      type: Number,
      default: 0
    },
    y: {
      type: Number,
      default: 0
    }
  }
}
</script>

Connection.vue :

<template>
  <svg class="connection">
    <!-- SVG 路径元素,用于绘制连接线 -->
    <path :d="path"></path>
  </svg>
</template>

<script>
export default {
  name: 'Connection',
  props: {
    start: Object,
    end: Object
  },
  computed: {
    path () {
      // 计算连接线的路径
      const startX = this.start.x + this.start.width / 2
      const startY = this.start.y + this.start.height / 2
      const endX = this.end.x + this.end.width / 2
      const endY = this.end.y + this.end.height / 2
      return `M ${startX} ${startY} L ${endX} ${endY}`
    }
  }
}
</script>

Nous utilisons le composant vue-draggable-resizing pour implémenter Pour faire glisser et mettre à l'échelle les nœuds, la largeur, la hauteur, x, y et d'autres attributs du nœud doivent être transmis. La ligne de connexion est tracée à l'aide de l'élément path de SVG et le chemin doit être calculé en fonction de la position et de la taille du nœud.

  1. Implémenter la fonction glisser-déposer

Afin d'implémenter la fonction glisser-déposer des nœuds, nous devons ajouter des écouteurs d'événement v-on:drag, v-on:dragstop et v-on:resize dans le composant Node . Ils correspondent respectivement au glisser, à la fin du glisser et au redimensionnement du nœud :

<draggable-resizable
  :w="width"
  :h="height"
  :x="x"
  :y="y"
  v-on:drag="onDrag"
  v-on:dragstop="onDragStop"
  v-on:resize="onResize"
>
  <!-- 节点的内容 -->
</draggable-resizable>

<script>
export default {
  name: 'Node',
  methods: {
    onDrag (pos) {
      // 拖拽事件处理函数
      this.$emit('move', {
        x: pos.x,
        y: pos.y
      })
    },
    onDragStop (pos) {
      // 结束拖拽事件处理函数
      this.$emit('endMove', {
        x: pos.x,
        y: pos.y
      })
    },
    onResize (size) {
      // 调整大小事件处理函数
      this.$emit('resize', {
        width: size.width,
        height: size.height
      })
    }
  }
}
</script>

Nous envoyons des événements au composant parent via la méthode $emit dans ces fonctions de gestion d'événements pour réaliser des mises à jour en temps réel de la position et de la taille du nœud. Dans le composant FlowChart, nous devons écouter ces événements et mettre à jour les informations du nœud :

<template>
  <div class="flowchart">
    <div class="nodes">
      <!-- 将节点插入到插槽中 -->
      <slot name="nodes"></slot>
    </div>
    <svg class="connections">
      <!-- 将连接线插入到插槽中 -->
      <slot name="connections"></slot>
      <!-- 鼠标跟随的连接线 -->
      <Connection v-if="showConnection"
                  :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}"
                  :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/>
    </svg>
  </div>
</template>

<script>
import Node from './Node.vue'
import Connection from './Connection.vue'

export default {
  name: 'FlowChart',
  components: {
    Node,
    Connection
  },
  data () {
    return {
      showConnection: false,
      start: null, // 起点节点
      end: null // 终点节点
    }
  },
  methods: {
    onNodeMove (node, pos) {
      // 节点拖拽时的事件处理函数
      node.x = pos.x
      node.y = pos.y
    },
    onNodeEndMove (node, pos) {
      // 节点结束拖拽时的事件处理函数
      node.x = pos.x
      node.y = pos.y
      this.showConnection = false
      this.start = null
      this.end = null
    },
    onNodeResize (node, size) {
      // 节点调整大小时的事件处理函数
      node.width = size.width
      node.height = size.height
    },
    connectNodes (start, end) {
      // 连接两个节点
      this.showConnection = true
      this.start = start
      this.end = end
    }
  }
}
</script>

Nous avons défini trois fonctions de gestion d'événements onNodeMove, onNodeEndMove et onNodeResize pour répondre au glissement, à la fin du glissement et au redimensionnement du nœud. La fonction connectNodes est utilisée pour connecter deux nœuds.

  1. Implémentation de la ligne de connexion

Dans le composant FlowChart, nous définissons une variable showConnection et deux variables start et end pour enregistrer les informations de la ligne de connexion. Nous devons mettre à jour ces informations via des événements de souris pour tracer la ligne de connexion.

Tout d'abord, nous devons ajouter l'écoute des événements v-on:mousedown et v-on:mouseup dans le composant Node. Ces événements sont utilisés pour détecter si l'utilisateur a sélectionné un nœud :

<draggable-resizable
  :w="width"
  :h="height"
  :x="x"
  :y="y"
  v-on:drag="onDrag"
  v-on:dragstop="onDragStop"
  v-on:resize="onResize"
  v-on:mousedown="onMouseDown"
  v-on:mouseup="onMouseUp"
>
  <!-- 节点的内容 -->
</draggable-resizable>

<script>
export default {
  name: 'Node',
  methods: {
    ...
    onMouseDown () {
      // 鼠标按下时选中当前节点
      this.$emit('select', this)
    },
    onMouseUp () {
      // 鼠标松开时取消选中
      this.$emit('unselect')
    }
  }
}
</script>

Nous envoyons un événement select au composant parent dans le gestionnaire d'événements onMouseDown pour sélectionner le nœud actuel. Dans le composant FlowChart, nous devons écouter cet événement :

<template>
  <div class="flowchart">
    <div class="nodes">
      <!-- 将节点插入到插槽中 -->
      <slot name="nodes"></slot>
    </div>
    <svg class="connections">
      <!-- 将连接线插入到插槽中 -->
      <slot name="connections"></slot>
      <!-- 鼠标跟随的连接线 -->
      <Connection v-if="showConnection"
                  :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}"
                  :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/>
    </svg>
  </div>
</template>

<script>
import Node from './Node.vue'
import Connection from './Connection.vue'

export default {
  name: 'FlowChart',
  components: {
    Node,
    Connection
  },
  data () {
    return {
      showConnection: false,
      start: null, // 起点节点
      end: null // 终点节点
    }
  },
  methods: {
    ...
    onSelectNode (node) {
      // 选中节点时的事件处理函数
      if (this.start) {
        // 已选择起点,连接当前节点
        this.end = node
        this.connectNodes(this.start, this.end)
      } else {
        // 选择起点
        this.start = node
      }
    },
    onUnselectNode () {
      // 取消选中节点时的事件处理函数
      this.start = null
      this.end = null
      this.showConnection = false
    }
  }
}
</script>

Nous déterminons si le nœud de point de départ est actuellement sélectionné dans la fonction de gestionnaire d'événements onSelectNode, et si c'est le cas, connectons le nœud actuel, sinon, définissons le nœud actuel comme ; point de départ. Dans le gestionnaire d'événements onUnselectNode, désélectionnez le nœud et réinitialisez les informations de la ligne de connexion.

  1. Réaliser l'édition de nœuds

Afin d'implémenter l'édition de nœuds, nous devons ajouter un bouton d'édition dans Node.vue et écouter son événement de clic :

<template>
  <draggable-resizable ...>
    <div class="node">
      <div class="node-content" v-on:click="$emit('edit')">
        <!-- 节点的内容 -->
      </div>
      <button class="edit-button" v-on:click="$emit('edit')">
        编辑
      </button>
    </div>
  </draggable-resizable>
</template>

<script>
export default {
  name: 'Node'
}
</script>

<style>
.edit-button {
  position: absolute;
  bottom: 5px;
  right: 5px;
}
</style>

Ensuite, écoutez l'événement d'édition dans FlowChart.vue, et select Afficher une zone de saisie sur le nœud :

<template>
  <div class="flowchart">
    <div class="nodes">
      <!-- 将节点插入到插槽中 -->
      <slot name="nodes"></slot>
    </div>
    <svg class="connections">
      <!-- 将连接线插入到插槽中 -->
      <slot name="connections"></slot>
      <!-- 鼠标跟随的连接线 -->
      <Connection v-if="showConnection"
                  :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}"
                  :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/>
    </svg>

    <!-- 编辑区域 -->
    <div class="edit-panel" v-if="selectedNode">
      <h3>编辑节点</h3>
      <form v-on:submit.prevent="saveNode">
        <label for="node-label">节点名称</label>
        <input id="node-label" type="text" v-model="nodeLabel">
        <button type="submit">保存</button>
      </form>
    </div>
  </div>
</template>

<script>
export default {
  name: 'FlowChart',
  data () {
    return {
      showConnection: false,
      start: null, // 起点节点
      end: null, // 终点节点
      selectedNode: null, // 选中的节点
      nodeLabel: '' // 当前节点的标签
    }
  },
  methods: {
    ...
    onSelectNode (node) {
      // 选中节点时的事件处理函数
      if (this.start) {
        // 已选择起点,连接当前节点
        this.end = node
        this.connectNodes(this.start, this.end)
        this.selectedNode = null
      } else {
        // 选择起点
        this.start = node
      }
    },
    onUnselectNode () {
      // 取消选中节点时的事件处理函数
      this.start = null
      this.end = null
      this.showConnection = false
      this.selectedNode = null
    },
    onEditNode (node) {
      // 编辑节点时的事件处理函数
      this.selectedNode = node
      this.nodeLabel = node.$slots.default[0].text.trim()
    },
    saveNode () {
      // 保存节点编辑后的信息
      this.selectedNode.$slots.default[0].text = this.nodeLabel
      this.selectedNode = null
    }
  }
}
</script>

<style>
.edit-panel {
  position: absolute;
  top: 0;
  right: 0;
  width: 300px;
  height: 100%;
  background: #fff;
  padding: 20px;
  box-shadow: -1px 0 10px rgba(0, 0, 0, 0.3);
}
</style>

Nous avons ajouté this.selectedNode = null dans la fonction de gestionnaire d'événements onSelectNode pour masquer la zone d'édition du nœud. Dans le gestionnaire d'événements onEditNode, nous envoyons un événement d'édition au composant parent pour afficher une zone de saisie permettant de modifier le nœud sélectionné. Nous enregistrons les informations modifiées du nœud dans la fonction de gestionnaire d'événements saveNode.

  1. Exporter l'organigramme

Enfin, nous pouvons ajouter un bouton d'exportation dans FlowChart.vue pour exporter l'organigramme actuel au format JSON :

<template>
  <div class="flowchart">
    <div class="nodes">
      <!-- 将节点插入到插槽中 -->
      <slot name="nodes"></slot>
    </div>
    <svg class="connections">
      <!-- 将连接线插入到插槽中 -->
      <slot name="connections"></slot>
      <!-- 鼠标跟随的连接线 -->
      <Connection v-if="showConnection"
                  :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}"
                  :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/>
    </svg>

    <!-- 编辑区域 -->
    ...

    <!-- 导出按钮 -->
    <button class="export-button" v-on:click="exportFlowchart">导出</button>
  </div>
</template>

<script>
export default {
  name: 'FlowChart',
  methods: {
    ...
    exportFlowchart () {
      // 导出流程图
      const nodes = []
      const connections = []
      this.$slots.nodes.forEach(vnode => {
        const node = vnode.componentInstance
        nodes.push({
          x: node.x,
          y: node.y,
          width: node.width,
          height: node.height,
          label: node.$slots.default[0].text.trim()
        })
      })

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn