VUE3+X6流程图实现数据双向绑定的方案

代码很简单,看看就可以了,不用多说。

定义组件:实现html节点与数据初始化、更新

html 复制代码
<script setup lang="ts">
import { Graph, Shape } from "@antv/x6";
import { onMounted, reactive, ref, watch } from "vue";
import useFlowModel from "./useFlowModel";
import flowdata from "./flowdata";

const container: any = ref(null);

Shape.HTML.register({
  shape: "custom-html",
  effect: ["data"],
  html(cell: any) {
    const { bgcolor, label } = cell.getData();
    return `<div style="background:${bgcolor};width:100%;height:100%;">${label}</div>`;
  },
});

const flowModel: any = reactive({
  graph: null,

  datatype: 0,
  modeldata: flowdata,
});
const { graphToModelData, modelDataToGraph, addNode, addNodeData } =
  useFlowModel(flowModel);

onMounted(() => {
  flowModel.graph = new Graph({
    container: container.value,
    // 设置画布背景颜色
    background: {
      color: "#F2F7FA",
    },
    height: 300,
    width: 600,
    grid: {
      visible: true,
      type: "doubleMesh",
      args: [
        {
          color: "#eee", // 主网格线颜色
          thickness: 1, // 主网格线宽度
        },
        {
          color: "#ddd", // 次网格线颜色
          thickness: 1, // 次网格线宽度
          factor: 4, // 主次网格线间隔
        },
      ],
    },
  });

  flowModel.graph.fromJSON(flowModel.modeldata); // 渲染元素
  flowModel.graph.centerContent(); // 居中显示

  flowModel.graph.on("cell:changed", (val: any) => {
    graphToModelData(val);
  });

  watch(
    () => flowModel.modeldata.cells.map((el: any) => JSON.stringify(el.data)),
    (newVal, oldVal) => {
      modelDataToGraph(newVal, oldVal);
    },
    { deep: true }
  );
});
</script>

<template>
  <template
    v-if="flowModel.modeldata?.cells && flowModel.modeldata?.cells[0]?.position"
  >
    <input type="number" v-model="flowModel.modeldata.cells[0].position.x" />
    <input type="text" v-model="flowModel.modeldata.cells[0].data.label" />
    <input type="text" v-model="flowModel.modeldata.cells[0].data.bgcolor" />
  </template>
  【{{ flowModel.modeldata?.cells && flowModel.modeldata?.cells[0].position }}】

  <button @click="addNode()">加G</button>
  <button @click="addNodeData()">加A</button>
  <button
    @click="console.log(666.1001, flowModel.modeldata.cells[0].x, flowModel)"
  >
    实时
  </button>
  <div id="container" ref="container"></div>
  <div class="as-show-model">{{ flowModel.modeldata }}</div>
</template>

<style scoped>
html,
body {
  margin: 0;
  padding: 0;
}
.as-show-model {
  display: inline-block;
  white-space: pre-wrap;
  overflow: auto;
  height: 300px;
  width: 300px;
}
.custom-html {
  outline: 1px dashed bisque;
}
#container {
  display: inline-block;
  background-color: rgb(248, 255, 240);
  margin-right: 8px;
  margin-left: 8px;
  border-radius: 5px;
  box-shadow: 0 12px 5px -10px rgb(0 0 0 / 10%), 0 0 4px 0 rgb(0 0 0 / 10%);
}
</style>

基本函数处理

typescript 复制代码
export default (flowModel: any) => {
  function modelDataToGraph(newVal: any, oldVal: any) {
    // console.log(666.333, oldVal, newVal);
    if (flowModel.datatype) {
      flowModel.datatype = 0;
    } else if (
      !oldVal?.length ||
      !newVal?.length ||
      oldVal?.length !== newVal?.length
    ) {
      flowModel.graph.fromJSON(flowModel.modeldata);
    } else {
      const nowCells: any = flowModel.graph.getCells();
      newVal.forEach((el: any, index: number) => {
        if (!oldVal.includes(el)) {
          flowModel.datatype = 2;
          nowCells[index].setProp({
            data: JSON.parse(el),
          });
        }
      });
    }
  }

  function graphToModelData(val: any) {
    // const { cell, options } = val;
    if (flowModel.datatype) {
      flowModel.datatype = 0;
    } else {
      flowModel.datatype = 1;
      flowModel.modeldata = flowModel.graph.toJSON();
    }
  }

  function addNodeData() {
    flowModel.modeldata.cells.push({
      position: {
        x: 30,
        y: 40,
      },
      size: {
        width: 100,
        height: 40,
      },
      data: {
        bgcolor: "#8f8f8f",
        label: "我是节点",
        color: "#333232",
        a: { B: 1 },
      },
      attrs: {
        text: {
          text: "我是节点",
        },
        body: {
          stroke: "#8f8f8f",
          strokeWidth: 1,
          fill: "#fff",
          rx: 6,
          ry: 6,
        },
      },
      visible: true,
      shape: "custom-html",
      id: "node1" + Date.now(),
      zIndex: 1,
    });
  }
  function addNode() {
    flowModel.graph.addNode({
      shape: "custom-html",
      x: 60,
      y: 100,
      width: 80,
      height: 40,
      data: {
        bgcolor: "#8f8f8f",
        label: "我是节点",
      },
    });
  }

  return { graphToModelData, modelDataToGraph, addNode, addNodeData };
};

演示数据

typescript 复制代码
export default {
  cells: [
    {
      position: {
        x: 30,
        y: 40,
      },
      size: {
        width: 120,
        height: 40,
      },
      data: {
        bgcolor: "#8f8f8f",
        label: "我是节点",
        color: "#333232",
        a: { B: 1 },
      },
      attrs: {},
      visible: true,
      shape: "custom-html",
      id: "node1",
      zIndex: 1,
    },
    {
      position: {
        x: 160,
        y: 180,
      },
      size: {
        width: 111,
        height: 40,
      },
      attrs: {
        text: { text: "世界你好" },
        body: {
          stroke: "#8f8f8f",
          strokeWidth: 1,
          fill: "#fff",
          rx: 6,
          ry: 6,
        },
      },
      visible: true,
      shape: "rect",
      id: "node2",
      zIndex: 1,
    },
    {
      position: {
        x: 190,
        y: 100,
      },
      size: {
        width: 160,
        height: 40,
      },
      data: {
        bgcolor: "#8f8f8f",
        label: "my test",
        color: "#333232",
        a: { B: 1 },
      },
      attrs: {},
      visible: true,
      shape: "custom-html",
      id: "node3",
      zIndex: 1,
    },
    {
      shape: "edge",
      attrs: {
        label: {
          text: "x6",
        },
        line: {
          stroke: "#8f8f8f",
          strokeWidth: 1,
        },
      },
      id: "0d9f0031-f018-413c-9631-1cd21d2f8c1f",
      source: {
        cell: "node1",
      },
      target: {
        cell: "node2",
      },
      labels: [
        {
          attrs: {
            label: {
              text: "x6",
            },
          },
        },
      ],
      zIndex: 1,
    },
  ],
};
相关推荐
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui
尝尝你的优乐美6 小时前
vue3.0中h函数的简单使用
前端·javascript·vue.js
windy1a6 小时前
【C语言】js写一个冒泡顺序
javascript