• vue3封装弹窗组件,数据回显
  1. 封装组件的流程,第一理解具体的业务需求。想好数据的交互层级,数据进数据出的具体逻辑。
  2. vue的组件封装记住一点不要在子组件修改父组件的数据,需要修改数据emit方法抛出数据父组件修改

. 第一步构建template模板

<template>
  <a-modal
    width="800.0px"
    v-model:visible="visible"
    @ok="handleOk"
    @cancel="handleCancel"
    :maskClosable="false"
  >
    <template #title> {{ title }} </template>
    <a-form ref="formRef" :model="state.form" :style="{ width: '600px' }">
      <a-form-item
        field="dictName"
        :rules="[{ required: true, message: '字典名称必填' }]"
        :validate-trigger="['change', 'input']"
        tooltip="输入字典名称"
        label="字典名称"
      >
        <a-input v-model="state.form.dictName" placeholder="输入字典名称" />
      </a-form-item>
      <a-form-item
        field="dictType"
        :rules="[{ required: true, message: '字典类型必填' }]"
        label="字典类型"
      >
        <a-input v-model="state.form.dictType" placeholder="输入字典类型" />
      </a-form-item>
      <a-form-item
        field="status"
        :rules="[{ required: true, message: '请选择状态' }]"
        label="状态"
      >
        <a-radio-group v-model="state.form.status">
          <a-radio value="0">正常</a-radio>
          <a-radio value="1">停用</a-radio>
        </a-radio-group>
      </a-form-item>
      <a-form-item field="remark">
        <a-textarea
          v-model="state.form.remark"
          placeholder="请输入内容"
          allow-clear
        />
      </a-form-item>
    </a-form>
  </a-modal>
</template>

这就是弹窗组件的一个基本dom结构。这个模板上看的话我们需要父组件传给我们两个值, 一个是弹窗的状态,一个是form表单的值。

. 第二步定义参数属性

const props = defineProps({
    visible: {
      type: Boolean,
      default: () => false,
    },
    formData: {
      type: Object as PropType<Dict.DictType>,
      default: () => {
        return {
          remark: '',
          dictId: 0,
          dictName: '',
          dictType: '',
          status: '0',
        };
      },
    },
  });

. 第三步就是子组件的赋值

const formRef = ref<FormInstance>();
  const state = reactive<Dict.State>({
    form: {
      remark: '',
      dictId: 0,
      dictName: '',
      dictType: '',
      status: '0',
    },
  });
  const { visible, formData } = toRefs(props);
  watch(
    () => formData,
    (value) => {
      state.form = value as unknown as Dict.DictType;
    },
    {
      immediate: true,
      deep: true,
    }
  );

接受父组件的formData需要使用toRefs结构不然传过来的值会丢失响应式。

最后把我们验证之后的formData值传递给父组件去调用接口就完成了,在这之前需要声明emit

  const emit = defineEmits(['handleClose', 'handleSubmitData']);
  
  const handleCancel = () => {
    emit('handleClose', false);
    formRef.value?.clearValidate();
  };
  const handleOk = () => {
    formRef?.value?.validate((r: any, Record: any) => {
      // eslint-disable-next-line no-void
      if (r == void 0) {
        emit('handleSubmitData', state.form);
        emit('handleClose', false);
      }
    });
  };

  • 通过emit的方法把子组件的数据传到父组件。

antv G6

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <title>Tutorial Demo</title>
</head>
<style>
    /* 提示框的样式 */
    .g6-tooltip {
        border: 1px solid #e2e2e2;
        border-radius: 4px;
        font-size: 12px;
        color: #545454;
        background-color: rgba(255, 255, 255, 0.9);
        padding: 10px 8px;
        box-shadow: rgb(174, 174, 174) 0px 0px 10px;
    }
</style>

<body>
    <!-- 引入 G6 -->
    <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.7.1/dist/g6.min.js"></script>
    <!-- 4.x and later versions -->
    <!-- <script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script> -->
<script src="https://unpkg.com/jquery@3.7.1/dist/jquery.js"></script>

    <div id="mountNode"></div>

    <button onclick="getNodes()">getNodes节点</button>

    <script>

        G6.registerNode('diamond', {
            draw(cfg, group) {
                // 如果 cfg 中定义了 style 需要同这里的属性进行融合
                const keyShape = group.addShape('path', {
                    attrs: {
                        path: this.getPath(cfg), // 根据配置获取路径
                        stroke: cfg.color, // 颜色应用到描边上,如果应用到填充,则使用 fill: cfg.color
                    },
                    // must be assigned in G6 3.3 and later versions. it can be any value you want
                    name: 'path-shape',
                    // 设置 draggable 以允许响应鼠标的图拽事件
                    draggable: true,
                });
                if (cfg.label) {
                    // 如果有文本
                    // 如果需要复杂的文本配置项,可以通过 labeCfg 传入
                    // const style = (cfg.labelCfg && cfg.labelCfg.style) || {};
                    // style.text = cfg.label;
                    const label = group.addShape('text', {
                        // attrs: style
                        attrs: {
                            x: 0, // 居中
                            y: 0,
                            textAlign: 'center',
                            textBaseline: 'middle',
                            text: cfg.label,
                            fill: '#666',
                        },
                        // must be assigned in G6 3.3 and later versions. it can be any value you want
                        name: 'text-shape',
                        // 设置 draggable 以允许响应鼠标的图拽事件
                        draggable: true,
                    });
                }
                return keyShape;
            },
            // 返回菱形的路径
            getPath(cfg) {
                const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
                const width = size[0];
                const height = size[1];
                //  / 1 \
                // 4     2
                //  \ 3 /
                const path = [
                    ['M', 0, 0 - height / 2], // 上部顶点
                    ['L', width / 2, 0], // 右侧顶点
                    ['L', 0, height / 2], // 下部顶点
                    ['L', -width / 2, 0], // 左侧顶点
                    ['Z'], // 封闭
                ];
                return path;
            },
            update(cfg, node) {
                debugger
                console.log(cfg, node);
                const group = node.getContainer(); // 获取容器
                const shape = group.get('children')[0]; // 按照添加的顺序
                const style = {
                    path: this.getPath(cfg),
                    stroke: cfg.color,
                };
                shape.attr(style); // 更新属性
                // 更新文本的逻辑类似,但是需要考虑 cfg.label 是否存在的问题
                // 通过 label.attr() 更新文本属性即可
            },
        });



        G6.registerNode('inner-animate', {
            afterDraw(cfg, group) {
                debugger
                const size = cfg.size;
                const width = size[0] - 14;
                const height = size[1] - 14;
                // 添加图片
                const image = group.addShape('image', {
                    attrs: {
                        x: - width / 2,
                        y: - height / 2,
                        width: width,
                        height: height,
                        img: cfg.img
                    },
                    // must be assigned in G6 3.3 and later versions. it can be any value you want
                    name: 'image-shape'
                });

            }
        },
            'rect');


        // 实例化 grid 插件
        const grid = new G6.Grid();

        const graph = new G6.Graph({
            container: 'mountNode', // 指定挂载容器
            width: 1300, // 图的宽度
            height: 1000, // 图的高度
            renderer: 'svg',
            defaultNode: {
                position: 'left',
                style: {
                    background: {
                        fill: '#ffffff',
                        stroke: 'green',
                        padding: [3, 2, 3, 2],
                        radius: 2,
                        lineWidth: 3,
                    },
                },
            },
            defaultEdge: {
                autoRotate: true,
                style: {
                    background: {
                        fill: '#ffffff',
                        stroke: '#000000',
                        padding: [2, 2, 2, 2],
                        radius: 2,
                    },
                },
            },
            nodeStateStyles: {
                // 各状态下的样式,平铺的配置项仅在 keyShape 上生效。需要在其他 shape 样式上响应状态变化则写法不同,参见上文提到的 配置状态样式 链接
                hover: {
                    fillOpacity: 0.1,
                    lineWidth: 10,
                },
            },
            plugins: [grid], // 将 grid 实例配置到图上
            // fitView: true,
            // fitViewPadding: [20, 40, 50, 20],
            modes: {
                default: ['drag-canvas', 'zoom-canvas', 'drag-node'
                    , {
                        type: 'tooltip', // 提示框
                        formatText(model) {
                            // 提示框文本内容
                            const text = 'label: ' + model.label + '<br/> class: ' + model.class;
                            return text;
                        },
                    },

                ], // 允许拖拽画布、放缩画布、拖拽节点
            },

            layout: {
                type: 'dagre',
                // 布局的方向。T:top(上);B:bottom(下);L:left(左);R:right(右)。
                rankdir: 'TB', // 可选,默认为图的中心
                // align: 'DL', // 可选
                nodesep: 20, // 可选
                ranksep: 50, // 可选
                controlPoints: true, // 可选
            },

            // layout: {
            //     // Object,可选,布局的方法及其配置项,默认为 random 布局。
            //     type: 'force', // 指定为力导向布局
            //     preventOverlap: true, // 防止节点重叠
            //     // nodeSize: 30        // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
            //     linkDistance: 300, // 指定边距离为100
            // },


        });

        const main = async () => {
            const response = await fetch(
                'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
            );
            const remoteData = await response.json();
            const data = {
                nodes: [
                    {
                        id: 'lusifer',
                        x: 100,
                        y: 100,
                        class: 'self_class',
                        label: 'rectvvva',
                        type: 'rect',
                        style: {
                            // 仅在 keyShape 上生效
                            fill: 'lightblue',
                            stroke: 'green',
                            lineWidth: 1,
                            radius: 1,
                        },
                        linkPoints: {
                            top: true,
                            bottom: true,
                            left: true,
                            right: true,
                            // ... 四个圆的样式可以在这里指定
                        },
                        // labelCfg: {...} // 标签的样式可以在这里指定
                    },
                ],
            };
            remoteData.edges.forEach(element => {
                // element.type = 'cubic-vertical';
                element.type = 'polyline';
                element.style = {
                    endArrow: true,
                    startArrow: true
                }
            });
            const datav = {
                nodes: [
                    { id: 'node1', x: 50, y: 100, color: 'red', type: 'diamond' }, // 最简单的
                    { id: 'node2', x: 150, y: 100, color: 'red', type: 'diamond', size: [50, 100] }, // 添加宽高

                    {
                        id: 'node3', x: 250, y: 100, color: 'red', type: 'inner-animate', size: [100, 100],
                        img: `./assets/img/info_1.png`
                    }, // 添加颜色

                    { id: 'node4', x: 350, y: 100, color: 'red', label: '菱形', type: 'diamond' }, // 附加文本
                ],
            };
            graph.data(remoteData); // 加载远程数据
            graph.render(); // 渲染
        };
        main();





        // 监听鼠标进入节点事件
        graph.on('node:mouseenter', (evt) => {
            const node = evt.item;
            // 激活该节点的 hover 状态
            graph.setItemState(node, 'hover', true);
        });
        // 监听鼠标离开节点事件
        graph.on('node:mouseleave', (evt) => {
            const node = evt.item;
            // 关闭该节点的 hover 状态
            graph.setItemState(node, 'hover', false);
        });

/**
 * 获取所有节点
 */
        function getNodes( ){
            let ns=    graph.getNodes();
debugger
            console.log(ns);
        
        }
        // graph.update(item, cfg)
    </script>
</body>

</html>