基於vue和jsplumb的工做流編輯器開發

背景

須要實現一個工做流,支持拖拽節點生成工做流。css

業務實現

  • 支持頁面佈局縮放
  • 支持節點
  • 支持if else
  • 支持多分支

技術點

  • 網格背景
  • 工做流縮放
  • 工做流技術實現
  • 節點拖拽

技術選型

  • vue
  • jsplumb
  • sortablejs(vue-draggable)

難點攻破

網格背景

主要是利用css的 linear-gradientbackground-size 實現的。html

<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;
}
複製代碼

.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;
}
複製代碼

工做流縮放

主要結合 css的 屬性選擇符 E[att="val"] ,經過修改zoom的值,來實現縮放功能。vue

<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;
}

複製代碼

工做流技術實現

主要是依賴 jsplumb 實現的。node

主要利用 jsplumb 實現兩個節點的鏈接。git

讓dom節點變成jsplumb 可拖拽節點

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

兩個節點的鏈接。

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}] //
    ]
});
複製代碼

刪除一個節點

jsPlumb.removeAllEndpoints(uuid);
複製代碼

兩個節點之間建立節點

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);
        });
    });
}
複製代碼

兩個節點之間的文案建立

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>`);
        }
    });
}
複製代碼

節點拖拽

主要是依賴 sortablejs 實現的github

主要利用vue-draggable 封裝好的組件,來實現拖拽。 核心代碼canvas

拖拽的目的地區域。dom

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

被拖拽的目標對象。jsp

<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>
複製代碼

項目截圖

項目地址

github: github.com/bosscheng/v…佈局

demo: bosscheng.github.io/vue-draggab…

相關文章
相關標籤/搜索