【组件库】使用Vue2+AntV X6+ElementUI 实现拖拽配置自定义vue节点 ...

打印 上一主题 下一主题

主题 1044|帖子 1044|积分 3132

    先来看看实现效果:

    【组件库】使用 AntV X6 + ElementUI 实现拖拽配置自定义 Vue 节点
在现代前端开辟中,流程图和可视化编辑器的需求日益增长。AntV X6 是一个强大的图形化框架,支持丰富的图形操纵和自定义功能。结合 ElementUI,我们可以轻松实现一个基于 Vue 的拖拽配置流程图,支持自定义节点和动态字段编辑。
一、技能栈介绍

AntV X6:一个基于 HTML5 Canvas 的图形化框架,支持流程图、拓扑图等多种图形化场景。


  • ElementUI:一个基于 Vue 的 UI 组件库,提供丰富的表单、表格和弹窗组件。
  • Vue.js:一个渐进式 JavaScript 框架,用于构建用户界面。
二、项目需求

我们的目标是实现一个流程图编辑器,支持以下功能:
拖拽添加节点:用户可以通过拖拽的方式在画布上添加自定义节点。
节点配置:通过弹窗对话框配置节点的属性,包罗实体名称和字段信息。
字段动态编辑:支持动态添加、删除字段,并提供字段类型选择。
数据导入导出:支持从 JSON 文件导入数据,以及将当前流程图导出为 JSON 文件。
三、实现步骤

1. 初始化项目

起首,确保你已经安装了 Vue CLI 和相关依赖。创建一个新的 Vue 项目,并安装以下依赖:
  1. vue create x6-vue-flow
  2. cd x6-vue-flow
  3. npm install @antv/x6 @antv/x6-plugin-dnd @antv/x6-vue-shape element-ui
复制代码
2. 创建主组件

在 src/components/FlowEditor.vue 中,实现流程图编辑器的主组件。以下是核心代码:
  1. <template>
  2.   <div class="flow-container">
  3.     <!-- 导航栏 -->
  4.     <div class="flow-nav">
  5.       <div class="add-entity" @mousedown="startDrag">添加实体</div>
  6.       <el-button type="primary" plain size="medium">保存</el-button>
  7.       <el-button type="warning" plain size="medium">清空</el-button>
  8.       <el-button type="success" plain size="medium">导出</el-button>
  9.       <el-upload accept=".json" :on-progress="handleOnProgress" action="" :show-file-list="false">
  10.         <el-button plain size="primary">导入</el-button>
  11.       </el-upload>
  12.     </div>
  13.     <!-- 画布 -->
  14.     <div class="flow-content">
  15.       <div id="container"></div>
  16.     </div>
  17.     <!-- 实体编辑对话框 -->
  18.     <el-dialog title="新增实体" :visible.sync="dialogVisible" width="45%">
  19.       <el-form ref="form" :model="formData" label-width="130px" :rules="rules" size="small">
  20.         <el-form-item prop="entity_name_CN" label="逻辑实体中文名">
  21.           <el-input v-model="formData.entity_name_CN" clearable></el-input>
  22.         </el-form-item>
  23.         <el-form-item prop="entity_name_EN" label="逻辑实体英文名">
  24.           <el-input v-model="formData.entity_name_EN" clearable></el-input>
  25.         </el-form-item>
  26.         <div class="field-container">
  27.           <div class="field-container__title">
  28.             <div class="primary-title">字段信息</div>
  29.             <el-button type="primary" size="small" icon="el-icon-plus" @click="addField">新增一行</el-button>
  30.           </div>
  31.           <el-table :data="formData.formField" height="250">
  32.             <el-table-column type="index" width="50" label="序号" align="center"></el-table-column>
  33.             <el-table-column prop="cname" label="字段中文名" width="150" align="center">
  34.               <template v-slot:default="{ $index }">
  35.                 <el-input size="small" v-model="formData.formField[$index].cname"></el-input>
  36.               </template>
  37.             </el-table-column>
  38.             <el-table-column prop="ename" label="字段英文名" width="200" align="center">
  39.               <template v-slot:default="{ $index }">
  40.                 <el-input size="small" v-model="formData.formField[$index].ename"></el-input>
  41.               </template>
  42.             </el-table-column>
  43.             <el-table-column prop="efType" label="字段类型" align="center">
  44.               <template v-slot:default="{ $index }">
  45.                 <el-select v-model="formData.formField[$index].efType" size="small">
  46.                   <el-option v-for="item in options" :key="item" :label="item" :value="item"></el-option>
  47.                 </el-select>
  48.               </template>
  49.             </el-table-column>
  50.             <el-table-column label="操作" fixed="right" align="center" width="80">
  51.               <template v-slot:default="{ $index }">
  52.                 <el-button type="danger" size="small" @click="handleFieldDelete($index)">删除</el-button>
  53.               </template>
  54.             </el-table-column>
  55.           </el-table>
  56.         </div>
  57.       </el-form>
  58.       <span slot="footer">
  59.         <el-button @click="dialogVisible = false">取消</el-button>
  60.         <el-button type="primary" @click="onSubmit(formData)">确定</el-button>
  61.       </span>
  62.     </el-dialog>
  63.   </div>
  64. </template>
  65. <script>
  66. import { Graph, Shape } from '@antv/x6';
  67. import { Dnd } from '@antv/x6-plugin-dnd';
  68. import { register } from '@antv/x6-vue-shape';
  69. import CellNode from './CellNode.vue';
  70. export default {
  71.   name: 'FlowEditor',
  72.   data() {
  73.     return {
  74.       graph: null,
  75.       dialogVisible: false,
  76.       formData: {
  77.         entity_name_CN: '',
  78.         entity_name_EN: '',
  79.         formField: [{ cname: '', ename: '', efType: '' }],
  80.       },
  81.       options: ['STRING', 'NUMBER', 'BOOLEAN', 'DATE', 'EMAIL'],
  82.     };
  83.   },
  84.   mounted() {
  85.     this.$nextTick(() => {
  86.       this.initGraph();
  87.     });
  88.   },
  89.   methods: {
  90.     initGraph() {
  91.       const container = document.getElementById('container');
  92.       const config = {
  93.         container,
  94.         width: '100%',
  95.         height: '100%',
  96.         autoResize: true,
  97.         panning: true,
  98.         mousewheel: true,
  99.       };
  100.       this.graph = new Graph(config);
  101.       const dnd = new Dnd({
  102.         target: this.graph,
  103.         validateNode: (node) => {
  104.           this.currentDragNode = node;
  105.           this.dialogVisible = true;
  106.           return false;
  107.         },
  108.       });
  109.       this.dnd = dnd;
  110.     },
  111.     startDrag(e) {
  112.       const node = this.graph.createNode({
  113.         shape: 'CellNode',
  114.       });
  115.       this.dnd.start(node, e);
  116.     },
  117.     onSubmit(data) {
  118.       this.dialogVisible = false;
  119.       const node = this.graph.addNode(this.currentDragNode);
  120.       node.setData(data);
  121.     },
  122.     addField() {
  123.       this.formData.formField.push({ cname: '', ename: '', efType: '' });
  124.     },
  125.     handleFieldDelete(index) {
  126.       this.formData.formField.splice(index, 1);
  127.     },
  128.   },
  129. };
  130. </script>
复制代码
3. 创建自定义 Vue 节点

在 src/components/CellNode.vue 中,实现自定义的 Vue 节点组件。以下是代码:
  1. <template>
  2.   <div style="background-color: #ffffff;">
  3.     <el-table :data="formData.formField" style="width: 100%" height="250">
  4.       <el-table-column label="资源名称" :formatter="() => formData.entity_name_CN"></el-table-column>
  5.       <el-table-column prop="cname" label="中文名"></el-table-column>
  6.       <el-table-column prop="ename" label="英文名"></el-table-column>
  7.       <el-table-column prop="efType" label="类型"></el-table-column>
  8.     </el-table>
  9.   </div>
  10. </template>
  11. <script>
  12. export default {
  13.   name: 'CellNode',
  14.   inject: ['getNode'],
  15.   data() {
  16.     return {
  17.       node: null,
  18.       formData: {
  19.         entity_name_CN: '',
  20.         entity_name_EN: '',
  21.         formField: [{ cname: '', ename: '', efType: '' }],
  22.       },
  23.     };
  24.   },
  25.   mounted() {
  26.     const node = this.getNode();
  27.     this.node = node;
  28.     node.on('change:data', (data) => {
  29.       if (data.cell && data.cell.data) {
  30.         this.formData = node.getData();
  31.       }
  32.     });
  33.   },
  34. };
复制代码
## 4. 注册自定义节点 在主组件中,使用 @antv/x6-vue-shape 注册自定义的 Vue 节点:
  1. import { register } from '@antv/x6-vue-shape';
  2. import CellNode from './CellNode.vue';
  3. register({
  4.   shape: 'CellNode',
  5.   width: 300,
  6.   height: 250,
  7.   component: CellNode,
  8. });
复制代码

  • 样式优化
    在 src/styles/index.scss 中,添加全局样式:
  1. .flow-container {
  2.   width: 100%;
  3.   height: 100%;
  4.   display: flex;
  5.   flex-direction: column;
  6.   .flow-nav {
  7.     display: flex;
  8.     align-items: center;
  9.     margin-bottom: 5px;
  10.     .add-entity {
  11.       border-radius: 6px;
  12.       background: rgba(64, 158, 255, 0.7);
  13.       border-color: #409eff;
  14.       border-style: dashed;
  15.       text-align: center;
  16.       color: #fff;
  17.       font-size: 14px;
  18.       padding: 5px;
  19.       box-sizing: content-box;
  20.       width: 100px;
  21.       cursor: pointer;
  22.     }
  23.   }
  24.   .flow-content {
  25.     flex: 1;
  26.   }
  27. }
复制代码
四、运行项目

完成以上步骤后,运行项目:
  1. npm run serve
复制代码
打开浏览器访问 http://localhost:8080,你将看到一个支持拖拽添加节点、动态字段编辑的流程图编辑器。
五、总结

    通过 AntV X6 和 ElementUI 的结合,我们实现了一个功能丰富的流程图编辑器。AntV X6 提供了强大的图形化能力,ElementUI 提供了丰富的 UI 组件,两者结合可以快速搭建出高效的可视化工具。
完备代码

Graph.vue代码

  1. // Graph.vue
  2. <template>
  3.     <div class="flow-container">
  4.         <!-- 导航栏 -->
  5.         <div class="flow-nav">
  6.             <div class="add-entity" @mousedown="startDrag">添加实体</div>
  7.             <el-button type="primary" style="margin-left: 10px" plain  size="medium">保存</el-button>
  8.             <el-button type="warning" style="margin-left: 10px" plain size="medium">清空</el-button>
  9.             <el-button type="success" style="margin-left: 10px" plain  size="medium">导出</el-button>
  10.             <el-upload accept=".JSON" :on-progress="handleOnProgress" action="" :show-file-list="false">
  11.                 <el-button plain size="primary" style="margin-left: 10px">导入</el-button>
  12.             </el-upload>
  13.         </div>
  14.         <!-- 画布 -->
  15.         <div class="flow-content" >
  16.             <div id="container"></div>
  17.         </div>
  18.         <!-- 实体编辑对话框 -->
  19.         <el-dialog class="dialog-box" title="新增实体" :visible.sync="dialogVisible" width="45%"  :before-close="handleClose" append-to-body="false">
  20.             <div class="content-wrapper">
  21.       <div class="primary-title">基本信息</div>
  22.       <el-form
  23.         ref="form"
  24.         :model="formData"
  25.         label-width="130px"
  26.         :rules="rules"
  27.         size="small"
  28.       >
  29.         <el-form-item prop="entity_name_CN" label="逻辑实体中文名">
  30.           <el-input v-model="formData.entity_name_CN" clearable></el-input>
  31.         </el-form-item>
  32.         <el-form-item prop="entity_name_EN" label="逻辑实体英文名">
  33.           <el-input v-model="formData.entity_name_EN" clearable></el-input>
  34.         </el-form-item>
  35.       <div class="field-container">
  36.         <div class="field-container__title">
  37.           <div class="primary-title">字段信息</div>
  38.           <div class="field-operation">
  39.             <el-button
  40.               type="primary"
  41.               size="small"
  42.               icon="el-icon-plus"
  43.               @click="addField"
  44.               >新增一行</el-button
  45.             >
  46.           </div>
  47.         </div>
  48.         <el-table :data="formData.formField" label-position="center" height="250">
  49.           <el-table-column type="index" width="50" label="序号" align="center">
  50.           </el-table-column>
  51.           <el-table-column
  52.             property="cname"
  53.             label="字段中文名"
  54.             width="150"
  55.             align="center"
  56.           >
  57.           <template v-slot:default="{ $index }" >
  58.             <el-input size="small" v-model="formData.formField[$index].cname"></el-input>
  59.           </template>
  60.         </el-table-column>
  61.           <el-table-column
  62.             property="ename"
  63.             label="字段英文名"
  64.             width="200"
  65.             align="center"
  66.           >
  67.           <template v-slot:default="{ $index }" >
  68.             <el-input size="small" v-model="formData.formField[$index].ename"></el-input>
  69.           </template>
  70.         </el-table-column>
  71.           <el-table-column
  72.             property="efType"
  73.             label="字段类型"
  74.             align="center"
  75.           >
  76.         <template v-slot:default="{ $index }">
  77.           <el-select
  78.           v-model="formData.formField[$index].efType"
  79.           default-first-option
  80.           placeholder="请选择字段类型"
  81.           clearable
  82.           size="small"
  83.         >
  84.           <el-option
  85.             v-for="item in options"
  86.             :key="item"
  87.             :label="item"
  88.             :value="item"
  89.           >
  90.           </el-option>
  91.         </el-select>
  92.         </template>
  93.         </el-table-column>
  94.           <el-table-column label="操作" fixed="right" align="center" width="80">
  95.             <template v-slot:default="{ $index }">
  96.               <el-button
  97.                 type="danger"
  98.                 size="small"
  99.                 @click="handleFieldDelete($index)"
  100.                 >删除</el-button
  101.               >
  102.             </template>
  103.           </el-table-column>
  104.         </el-table>
  105.       </div>
  106.     </el-form>
  107.     </div>
  108.             <span slot="footer" class="dialog-footer">
  109.                 <el-button @click="dialogVisible = false">取 消</el-button>
  110.                 <el-button type="primary" @click="onSubmit(formData)">确 定</el-button>
  111.             </span>
  112.         </el-dialog>
  113.     </div>
  114. </template>
  115. <script>
  116. // import index from '../../index.js'
  117. import { Graph, Shape } from '@antv/x6'
  118. import { Dnd } from '@antv/x6-plugin-dnd'
  119. import { register } from '@antv/x6-vue-shape'
  120. import CellNode from './components/cellNode.vue'
  121. // 画布配置
  122. const config = {
  123.   container: null,
  124.   width: '100%',
  125.   height: '100%',
  126.   autoResize: true,
  127.   // 拖拽画布
  128.   panning: true,
  129.   mousewheel: true,
  130.   connecting: {
  131.     snap: true, // 是否开启连线自动吸附
  132.     highlight: true, // 是否高亮显示连线
  133.     router: 'manhattan',
  134.     connectionPoint: 'anchor',
  135.     anchor: 'center',
  136.     allowBlank: false,
  137.     // 不允许创建循环连线,即边的起始节点和终止节点为同一节点
  138.     allowEdge: false,
  139.     // 不允许起点终点相同
  140.     allowLoop: false,
  141.     //  是否允许边连接到非节点上
  142.     allowNode: false,
  143.     // 起始和终止节点的相同连接桩之间只允许创建一条边
  144.     allowMulti: 'witPort'
  145.   },
  146.   background: {
  147.     color: '#F2F7FA'
  148.   },
  149.   grid: {
  150.     visible: true,
  151.     type: 'doubleMesh',
  152.     args: [
  153.       {
  154.         color: '#eee', // 主网格线颜色
  155.         thickness: 1 // 主网格线宽度
  156.       },
  157.       {
  158.         color: '#ddd', // 次网格线颜色
  159.         thickness: 1, // 次网格线宽度
  160.         factor: 4 // 主次网格线间隔
  161.       }
  162.     ]
  163.   }
  164. }
  165. // 连接桩配置
  166. const ports = {
  167.   groups: {
  168.     // 对话框需要的一些外部数据
  169.     right: {
  170.       position: 'right',
  171.       attrs: {
  172.         circle: {
  173.           r: 5,
  174.           magnet: true,
  175.           stroke: '#5F95FF',
  176.           strokeWidth: 1,
  177.           fill: '#fff'
  178.         }
  179.       }
  180.     },
  181.     left: {
  182.       position: 'left',
  183.       attrs: {
  184.         circle: {
  185.           r: 5,
  186.           magnet: true,
  187.           stroke: '#5F95FF',
  188.           strokeWidth: 1,
  189.           fill: '#fff'
  190.         }
  191.       }
  192.     }
  193.   }
  194. }
  195. // 注册HTML节点
  196. Shape.HTML.register({
  197.   shape: 'custom-html',
  198.   width: 160,
  199.   height: 80,
  200.   effect: ['data'],
  201.   html (formData) {
  202.     const data = formData
  203.     const div = document.createElement('div')
  204.     div.className = 'custom-html'
  205.     const span1 = document.createElement('span')
  206.     const span2 = document.createElement('span')
  207.     const span3 = document.createElement('span')
  208.     span1.innerText = '1111'
  209.     span2.innerText = '2222'
  210.     span3.innerText = '3333'
  211.     div.appendChild(span1)
  212.     div.appendChild(span2)
  213.     div.appendChild(span3)
  214.     return div
  215.   }
  216. })
  217. // 注册Vue节点
  218. register({
  219.   shape: 'CellNode',
  220.   width: 300,
  221.   height: 250,
  222.   component: CellNode,
  223.   ports: {
  224.     ...ports,
  225.     items: [{ group: 'left' }, { group: 'right' }]
  226.   }
  227. })
  228. // 注册边
  229. Graph.registerEdge(
  230.   'dag-edge',
  231.   {
  232.     inherit: 'edge',
  233.     attrs: {
  234.       line: {
  235.         stroke: '#C2C8D5',
  236.         strokeWidth: 1,
  237.         targetMarker: null
  238.       }
  239.     }
  240.   },
  241.   true
  242. )
  243. export default {
  244.   name: 'vue-flow',
  245.   data () {
  246.     return {
  247.       graph: null,
  248.       currentEdge: null,
  249.       dnd: null,
  250.       dialogVisible: false,
  251.       currentDragNode: null,
  252.       // 对话框类型 编辑/新增
  253.       formData: {
  254.         entity_name_CN: '',
  255.         entity_name_EN: '',
  256.         // field_list: [],
  257.         formField: [{
  258.           cname: '',
  259.           ename: '',
  260.           efType: ''
  261.         }]
  262.       },
  263.       options: [
  264.         'STRING',
  265.         'NUMBER',
  266.         'BOOLEAN',
  267.         'DATE',
  268.         'EMAIL',
  269.         'URL',
  270.         'ARRAY',
  271.         'OBJECT',
  272.         'TEXTAREA',
  273.         'SELECT',
  274.         'RADIO',
  275.         'CHECKBOX',
  276.         'PASSWORD',
  277.         'FILE',
  278.         'IMAGE',
  279.         'RANGE',
  280.         'COLOR',
  281.         'TEL',
  282.         'SEARCH',
  283.         'DATETIME',
  284.         'DATETIME_LOCAL',
  285.         'MONTH',
  286.         'WEEK',
  287.         'TIME',
  288.         'HIDDEN'
  289.       ],
  290.       rules: {
  291.         entity_name_CN: [
  292.           { required: true, trigger: 'blur', message: '请输入逻辑实体中文名' }
  293.         ],
  294.         entity_name_EN: [
  295.           { required: true, trigger: 'blur', message: '请输入逻辑实体英文名' }
  296.         ]
  297.       }
  298.     }
  299.   },
  300.   provide () {
  301.     return {
  302.       // 要用箭头函数保证this在其他组件获取正确
  303.       getGraph: () => {
  304.         return this.graph
  305.       }
  306.     }
  307.   },
  308.   mounted () {
  309.     this.$nextTick(() => {
  310.       this.initGraph()
  311.     })
  312.   },
  313.   methods: {
  314.     initGraph () {
  315.       // 容器dom
  316.       const container = document.getElementById('container')
  317.       config.container = container
  318.       // 实例化画布
  319.       this.graph = new Graph(config)
  320.       // 实例化拖拽节点
  321.       const dnd = new Dnd({
  322.         target: this.graph,
  323.         validateNode: (node) => {
  324.           this.currentDragNode = node
  325.           this.dialogVisible = true
  326.           return false
  327.         }
  328.       })
  329.       this.dnd = dnd
  330.       this.graph.centerContent() // 居中显示
  331.     },
  332.     startDrag (e) {
  333.       const node = this.graph.createNode({
  334.         shape: 'CellNode'
  335.       })
  336.       this.dnd.start(node, e)
  337.     },
  338.     handleClose (done) {
  339.       this.$confirm('确认关闭?')
  340.         .then(_ => {
  341.           done()
  342.         })
  343.         .catch(_ => {})
  344.     },
  345.     // 添加节点
  346.     addNode (node) {
  347.       return this.graph.addNode(node)
  348.     },
  349.     onSubmit (data) {
  350.       this.dialogVisible = false
  351.       if (this.currentDragNode) {
  352.         const node = this.addNode(this.currentDragNode)
  353.         const dataSource = {
  354.           ...data
  355.         }
  356.         // TODO 有异步问题需要处理先写死200ms
  357.         setTimeout(() => {
  358.           node.setData(dataSource)
  359.         }, 200)
  360.       }
  361.     },
  362.     addField () {
  363.       this.formData.formField.push({
  364.         cname: '',
  365.         ename: '',
  366.         efType: ''
  367.       })
  368.     },
  369.     handleFieldDelete () {
  370.       this.formData.formField.splice(0, 1)
  371.     }
  372.   }
  373. }
  374. </script>
  375. <style lang="scss">
  376. $height: 40px;
  377. .custom-html {
  378.   display: flex;
  379.     width: 100%;
  380.     height: 100%;
  381.     align-items: center;
  382.     background-color: #fff;
  383.     span {
  384.       display: inline-block;
  385.       height: $height;
  386.       line-height: $height;
  387.       border: 1px solid #0f7bcc;
  388.       text-align: center;
  389.       min-width: 0;
  390.       flex: 1;
  391.     }
  392. }
  393. .flow-container {
  394.     width: 100%;
  395.     height: 100%;
  396.     display: flex;
  397.     flex-direction: column;
  398.     .flow-nav {
  399.         display: flex;
  400.         align-items: center;
  401.         margin-bottom: 5px;
  402.         .add-entity {
  403.             border-radius: 6px;
  404.             background: rgba(64, 158, 255, 0.7);
  405.             background-clip: padding-box;
  406.             border-color: #409eff;
  407.             border-style: dashed;
  408.             text-align: center;
  409.             color: #fff;
  410.             font-size: 14px;
  411.             padding: 5px;
  412.             box-sizing: content-box;
  413.             width: 100px;
  414.             cursor: pointer;
  415.         }
  416.     }
  417.     .flow-content {
  418.         flex: 1;
  419.     }
  420.     .my-selecting {
  421.         border: 1px dashed #40ff7c;
  422.         background-color: #0f7bcc;
  423.     }
  424.     .x6-widget-selection-box {
  425.         border: 0px dashed rgba(0, 0, 0, 0);
  426.         box-shadow: 1px 1px 10px 0 rgba(0, 0, 0, 0.3);
  427.         border-radius: 6px;
  428.         // background-color: #0F7BCC;
  429.         // opacity: 0.1;
  430.     }
  431.     .x6-widget-selection-inner {
  432.         opacity: 0.1;
  433.         border: 5px solid #000000;
  434.         background-color: #0f7bcc;
  435.     }
  436. }
  437. .dialog-box{
  438.   // width: 600%;
  439.   // height: 800px;
  440.   .el-dialog__title{
  441.   color:#fff;
  442.   font-size: 18px;
  443. }
  444. .content-wrapper {
  445.   padding:15px;
  446.   .primary-title {
  447.     font-size: 18px;
  448.     font-weight: 700;
  449.     padding-bottom: 10px;
  450.   }
  451.   .field-container {
  452.     &__title {
  453.       display: flex;
  454.       justify-content: space-between;
  455.     }
  456.   }
  457. }
  458. }
  459. </style>
复制代码
cellNode.vue代码

[code]<template>
  <div style="background-color:  #ffffff;">
    <el-table
      :data="formData.formField"
      style="width: 100%"
      height="250"
    >
      <el-table-column :label="`资源名称:${formData.entity_name_CN}`">
      <el-table-column
        prop="cname"
        label="中文名"
      >
      </el-table-column>
      <el-table-column
        prop="ename"
        label="英文名"
      >
      </el-table-column>
      <el-table-column
        prop="efType"
        label="类型"
      >
      </el-table-column>
    </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: 'CellNode',
  inject: ['getNode'],
  data () {
    return {
      // 当前实体节点
      node: null,
      formData: {
        entity_name_CN: '',
        entity_name_EN: '',
        formField: [
          {
            cname: '',
            ename: '',
            efType: ''
          }
        ]
      }
    }
  },
  mounted () {
    // 获取node节点
    const node = this.getNode()
    this.node = node
    // 节点data改变监听
    node.on('change:data', (data) => {
      if (data.cell && data.cell.data) {
        this.formData = node.getData()
        console.log('

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

反转基因福娃

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表