Desarrollo de editor de flujo de trabajo basado en vue y jsplumb

antecedentes

Debe implementar un flujo de trabajo que admita arrastrar y soltar nodos para generar un flujo de trabajo.

Realización empresarial

  • Zoom de diseño de página de soporte
  • Nodo de soporte
  • Apoyar si más
  • Soporta múltiples ramas

Punto técnico

  • Fondo de cuadrícula
  • Zoom del flujo de trabajo
  • Realización de tecnología de flujo de trabajo
  • Arrastre de nodo

Selección de tecnología

  • vista
  • jsplumb
  • sortablejs (vue-draggable)

Dificultades para romper

Fondo de cuadrícula

Utilizando principalmente el CSS linear-gradienty la background-sizeimplementación.

<div class="flow-layout">
    <div class="flow-editor">
        <div class="canvas-container">
        </div>
    </div>
</div>
.flow-layout {
    
    
  display: flex;
  flex-direction: column;
}

.flow-editor {
    
    
  position: relative;
  display: flex;
  flex-direction: row;
  flex: 1;
  overflow: hidden;
}

.canvas-container {
    
    
  flex: 1;
  overflow: auto;
  z-index: 0;
}

Inserte la descripción de la imagen aquí

.canvas-container:before {
    
    
  content: "";
  height: 10px;
  width: 100%;
  display: block;
  background-repeat-y: no-repeat;
  position: absolute;
  background-image: linear-gradient(90deg, #ccc 1px, transparent 0), linear-gradient(90deg, #ddd 1px, transparent 0);
  background-size: 75px 10px, 5px 5px;
}

.canvas-container:after {
    
    
  content: "";
  height: 100%;
  width: 10px;
  display: block;
  background-repeat-x: no-repeat;
  position: absolute;
  top: 0;
  background-image: linear-gradient(#ccc 1px, transparent 0), linear-gradient(#ddd 1px, transparent 0);
  background-size: 10px 75px, 5px 5px;
}

Zoom del flujo de trabajo

Principalmente combinado con el selector de atributos de CSS E[att="val"], la función de zoom se realiza modificando el valor de zoom.

Inserte la descripción de la imagen aquí

<div class="flow-zoom" :data-zoom="canvasDataRoom + '%'">
    <div class="zoom-btn">
        <el-button size="mini" :class="{
     
     'el-button--primary':canvasRoomMinusEnable}" icon="el-icon-minus"
                   circle
                   @click="handleMinusCanvas"></el-button>
    </div>
    <div class="zoom-btn">
        <el-button size="mini" :class="{
     
     'el-button--primary':canvasRoomPlusEnable}" icon="el-icon-plus"
                   circle
                   @click="handlePlusCanvas"></el-button>
    </div>
</div>


<div class="canvas-container" :data-zoom="canvasDataRoom">
    <div class="campaignCanvas"></div>
</div>
.canvas-container[data-zoom="100"] {
    
    
  background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  background-size: 75px 75px, 75px 75px, 15px 15px, 15px 15px;
}

.canvas-container[data-zoom="90"] {
    
    
  background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  background-size: 70px 70px, 70px 70px, 14px 14px, 14px 14px;
}

.canvas-container[data-zoom="80"] {
    
    
  background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  background-size: 60px 60px, 60px 60px, 12px 12px, 12px 12px;
}

.canvas-container[data-zoom="70"] {
    
    
  background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  background-size: 55px 55px, 55px 55px, 11px 11px, 11px 11px;
}

.canvas-container[data-zoom="60"] {
    
    
  background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  background-size: 45px 45px, 45px 45px, 9px 9px, 9px 9px;
}

.canvas-container[data-zoom="50"] {
    
    
  background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  background-size: 40px 40px, 40px 40px, 8px 8px, 8px 8px;
}

Realización de tecnología de flujo de trabajo

Confíe principalmente en jsplumb para lograrlo.

Utilice principalmente jsplumb para realizar la conexión de dos nodos.

Deje que el nodo dom se convierta en un nodo arrastrable jsplumb

<div id="_uuid">
</div>
jsPlumb.draggable(_uuid, {
    
    });

Conexión de dos nodos.

jsPlumb.connect({
    
    
    source: source,
    target: target,
    endpoint: 'Dot',
    // 连接线的样式
    connectorStyle: {
    
    strokeStyle: "#ccc", joinStyle: "round", outlineColor: "#ccc"}, // 链接 style
    // 连接线配置,起点可用
    connector: ["Flowchart", {
    
    
        stub: [10, 20],
        gap: 1,
        cornerRadius: 2,
        alwaysRespectStubs: true
    }], //  链接
    //
    endpointStyle: {
    
    fill: 'transparent', outlineStroke: 'transparent', outlineWidth: 2},
    // 线的样式
    paintStyle: {
    
    stroke: 'lightgray', strokeWidth: 2},
    // 锚点的位置
    anchor: ['BottomCenter', 'TopCenter'],
    // 遮罩层-设置箭头
    overlays: [
        ['PlainArrow', {
    
    width: 10, length: 10, location: 1}],
        ['Custom', {
    
    
            location: .5,
            id: 'nodeTempSmall',
            create: function () {
    
    
                let $el = that.$refs[target][0].$el;
                $el.dataset.target = target;
                $el.dataset.source = source;
                return $el;
            },
            visible: false
        }],
        ['Label', {
    
    location: 1, id: "flowItemDesc", cssClass: "node-item-label", visible: true}] //
    ]
});

Eliminar un nodo

jsPlumb.removeAllEndpoints(uuid);

Crea un nodo entre dos nodos

Inserte la descripción de la imagen aquí

 function createFlowConnectionLabel(sourceList, target) {
    
    

    if (!Array.isArray(sourceList)) {
    
    
        sourceList = [sourceList];
    }

    sourceList.forEach((source) => {
    
    
        //
        let lines = this.$options.jsPlumb.getConnections({
    
    
            source: source,
            target: target
        });
        //
        lines.forEach((line) => {
    
    
            line.getOverlay('nodeTempSmall').setVisible(true);
            line.bind('click', this.handleFlowLabelClick);
        });
    });
}

Redacción publicitaria entre dos nodos

Inserte la descripción de la imagen aquí

 function createFlowItemLabel(source, target, label) {
    
    
    this.$nextTick(() => {
    
    
        let lines = this.$options.jsPlumb.getConnections({
    
    
            source: source,
            target: target
        });
        if (lines.length > 0) {
    
    
            lines[0].getOverlay("flowItemDesc").setLabel(`<span class="node-item-title" title="${
      
      label}">${
      
      label}</span>`);
        }
    });
}

Arrastre de nodo

Confíe principalmente en sortablejs para lograr

Utilice principalmente componentes encapsulados que se pueden arrastrar mediante vue para lograr la función de arrastrar y soltar. Código de núcleo

El área de destino arrastrada.

<draggable class="flow-item node-temp node-temp-img"
           ref="tempNode"
           :id="flowItem.uuid"
           :group="{name:'sortable', pull:false, put: true }">
</draggable>

El objeto de destino que se está arrastrando.

<draggable class="items-box"
           :key="index"
           :list="flowItem.children"
           :group="{name:'sortable', pull: 'clone', put: false }"
           v-bind="dragConfig"
           :move="handleFlowMoveItem"
           @start="handleFlowMoveStart"
           @end="handleFlowMoveEnd"
           :sort="false"
           :ref="flowItem.ref">
        <div class="node-temp-img"></div>
    </template>
</draggable>

Captura de pantalla del proyecto

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

dirección del proyecto

github: https://github.com/bosscheng/vue-draggable-workflow

demostración: https://bosscheng.github.io/vue-draggable-workflow

Supongo que te gusta

Origin blog.csdn.net/wancheng815926/article/details/105842539
Recomendado
Clasificación