您好,登錄后才能下訂單哦!
這篇文章主要介紹“vue+jsplumb實現工作流程圖的方法”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“vue+jsplumb實現工作流程圖的方法”文章能幫助大家解決問題。
先寫了一個demo,大概樣子如下:
官網文檔Home | jsPlumb Toolkit Documentation
先安裝插件
npm install jsplumb --save
安裝panzoom,主要用于鼠標滾輪縮放流程圖
npm install panzoom --save
在需要的頁面引入插件
import panzoom from 'panzoom' import { jsPlumb } from 'jsplumb'
接下來先寫布局
父組件
<template> <div class="workflow"> <div class="flow_region"> <div id="flowWrap" ref="flowWrap" class="flow-wrap" @drop="drop($event)" @dragover="allowDrop($event)"> <div id="flow"> <flowNode v-for="item in data.nodeList" :id="item.id" :key="item.id" :node="item" @setNodeName="setNodeName" @changeLineState="changeLineState" /> </div> </div> </div> </div> </template>
flowNode是子組件
<template> <div ref="node" class="node-item" :class="{ isStart: node.type === 'start', isEnd: node.type === 'end', 'common-circle-node':node.type === 'start' || node.type === 'end' || node.type === 'event', 'common-rectangle-node':node.type === 'common' || node.type === 'freedom' || node.type === 'child-flow', 'common-diamond-node':node.type === 'gateway', 'common-x-lane-node':node.type === 'x-lane', 'common-y-lane-node':node.type === 'y-lane' }" :style="{ top: node.y + 'px', left: node.x + 'px' }" @click="setNotActive" @mouseenter="showAnchor" @mouseleave="hideAnchor" > <div class="nodeName">{{ node.nodeName }}</div> </div> </template>
樣式主要是子組件的,父組件樣式隨意就行
<style lang="less" scoped> @labelColor: #409eff; @nodeSize: 20px; @viewSize: 10px; .node-item { position: absolute; display: flex; height: 40px; width: 120px; justify-content: center; align-items: center; border: 1px solid #b7b6b6; border-radius: 4px; cursor: move; box-sizing: content-box; font-size: 12px; z-index: 9995; &:hover { z-index: 9998; .delete-btn{ display: block; } } .log-wrap{ width: 40px; height: 40px; border-right: 1px solid #b7b6b6; } .nodeName { flex-grow: 1; width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; } .node-anchor { display: flex; position: absolute; width: @nodeSize; height: @nodeSize; align-items: center; justify-content: center; border-radius: 10px; cursor: crosshair; z-index: 9999; background: -webkit-radial-gradient(sandybrown 10%, white 30%, #9a54ff 60%); } .anchor-top{ top: calc((@nodeSize / 2)*-1); left: 50%; margin-left: calc((@nodeSize/2)*-1); } .anchor-right{ top: 50%; right: calc((@nodeSize / 2)*-1); margin-top: calc((@nodeSize / 2)*-1); } .anchor-bottom{ bottom: calc((@nodeSize / 2)*-1); left: 50%; margin-left: calc((@nodeSize / 2)*-1); } .anchor-left{ top: 50%; left: calc((@nodeSize / 2)*-1); margin-top: calc((@nodeSize / 2)*-1); } } .active{ border: 1px dashed @labelColor; box-shadow: 0px 5px 9px 0px rgba(0,0,0,0.5); } .common-circle-node{ border-radius: 50%; height: 60px; width: 60px; } </style>
頁面樣式寫完,接下來寫插件配置
jsPlumb.ready() 是一個鉤子函數,它會在 jsPlumb 準備完畢時執行。
連接線的建立是通過 jsPlumb.connect() 方法實現的。該方法接受一個對象作為配置項。其中包含了與上述概念一一對應的配置項,以及一些額外的樣式。
source: 源對象,可以是對象的 id 屬性、Element 對象或者 Endpoint 對象。
target: 目標對象,可以是對象的 id 屬性、Element 對象或者 Endpoint 對象。
anchor: 是一個數組,數組中每一項定義一個錨點。
初始化方法
init() { this.jsPlumb.ready(() => { // 導入默認配置 this.jsPlumb.importDefaults(this.jsplumbSetting) // 完成連線前的校驗 this.jsPlumb.bind('beforeDrop', evt => { const res = () => { } // 此處可以添加是否創建連接的校驗, 返回 false 則不添加; return res }) this.loadEasyFlow() // 會使整個jsPlumb立即重繪。 this.jsPlumb.setSuspendDrawing(false, true) }) this.initPanZoom() }, // 加載流程圖 loadEasyFlow() { // 初始化節點 for (let i = 0; i < this.data.nodeList.length; i++) { const node = this.data.nodeList[i] // 設置源點,可以拖出線連接其他節點 this.jsPlumb.makeSource(node.id, this.jsplumbSourceOptions) // // 設置目標點,其他源點拖出的線可以連接該節點 this.jsPlumb.makeTarget(node.id, this.jsplumbTargetOptions) // this.jsPlumb.draggable(node.id); this.draggableNode(node.id) } // 初始化連線 this.jsPlumb.unbind('connection') // 取消連接事件 console.log(this.data.lineList) for (let i = 0; i < this.data.lineList.length; i++) { const line = this.data.lineList[i] const conn = this.jsPlumb.connect( { source: line.sourceId, target: line.targetId, paintStyle: { stroke: line.cls.linkColor, strokeWidth: 2 // strokeWidth: line.cls.linkThickness } }, this.jsplumbConnectOptions ) conn.setLabel({ label: line.label, cssClass: `linkLabel ${line.id}` }) } },
this.data 是需要渲染的數據,放在文章末尾,具體數據按照接口實際返回的來寫
this.jsplumbSourceOptions 是jsplumb配置信息,新建一個文件編寫,具體如下:
export const jsplumbSetting = { grid: [10, 10], // 動態錨點、位置自適應 anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'], Container: 'flow', // 連線的樣式 StateMachine、Flowchart,有四種默認類型:Bezier(貝塞爾曲線),Straight(直線),Flowchart(流程圖),State machine(狀態機) Connector: ['Flowchart', { cornerRadius: 5, alwaysRespectStubs: true, stub: 5 }], // 鼠標不能拖動刪除線 ConnectionsDetachable: false, // 刪除線的時候節點不刪除 DeleteEndpointsOnDetach: false, // 連線的端點 // Endpoint: ["Dot", {radius: 5}], Endpoint: [ 'Rectangle', { height: 10, width: 10 } ], // 線端點的樣式 EndpointStyle: { fill: 'rgba(255,255,255,0)', outlineWidth: 1 }, LogEnabled: false, // 是否打開jsPlumb的內部日志記錄 // 繪制線 PaintStyle: { stroke: '#409eff', strokeWidth: 2 }, HoverPaintStyle: { stroke: '#409eff' }, // 繪制箭頭 Overlays: [ [ 'Arrow', { width: 8, length: 8, location: 1 } ] ], RenderMode: 'svg' } // jsplumb連接參數 export const jsplumbConnectOptions = { isSource: true, isTarget: true, // 動態錨點、提供了4個方向 Continuous、AutoDefault anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'] } export const jsplumbSourceOptions = { filter: '.node-anchor', // 觸發連線的區域 /* "span"表示標簽,".className"表示類,"#id"表示元素id*/ filterExclude: false, anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'], allowLoopback: false } export const jsplumbTargetOptions = { filter: '.node-anchor', /* "span"表示標簽,".className"表示類,"#id"表示元素id*/ filterExclude: false, anchor: ['TopCenter', 'RightMiddle', 'BottomCenter', 'LeftMiddle'], allowLoopback: false }
在父組件引入配置文件和方法
import { jsplumbSetting, jsplumbConnectOptions, jsplumbSourceOptions, jsplumbTargetOptions } from './config/commonConfig'
接下來在上面說的初始化方法文件里面配置鼠標滾輪縮放插件的方法 this.initPanZoom():
// 鼠標滾動放大縮小 initPanZoom() { const mainContainer = this.jsPlumb.getContainer() const mainContainerWrap = mainContainer.parentNode const pan = panzoom(mainContainer, { smoothScroll: false, bounds: true, // autocenter: true, zoomDoubleClickSpeed: 1, minZoom: 0.5, maxZoom: 2, // 設置滾動縮放的組合鍵,默認不需要組合鍵 beforeWheel: (e) => { // console.log(e) // let shouldIgnore = !e.ctrlKey // return shouldIgnore }, beforeMouseDown: function(e) { // allow mouse-down panning only if altKey is down. Otherwise - ignore var shouldIgnore = e.ctrlKey return shouldIgnore } }) this.jsPlumb.mainContainerWrap = mainContainerWrap this.jsPlumb.pan = pan // 縮放時設置jsPlumb的縮放比率 pan.on('zoom', e => { const { scale } = e.getTransform() this.jsPlumb.setZoom(scale) }) pan.on('panend', (e) => { }) // 平移時設置鼠標樣式 mainContainerWrap.style.cursor = 'grab' mainContainerWrap.addEventListener('mousedown', function wrapMousedown() { this.style.cursor = 'grabbing' mainContainerWrap.addEventListener('mouseout', function wrapMouseout() { this.style.cursor = 'grab' }) }) mainContainerWrap.addEventListener('mouseup', function wrapMouseup() { this.style.cursor = 'grab' }) },
大功告成,data的數據放在這里,測試使用:
{ "FlowJson": { "nodeList": [ { "type": "start", "nodeName": "已新建", "id": "start-HiXWf8wsAcrWXjAAXVWc6AQk00000001", "node_code": "已新建", "trigger_event": "", "branch_flow": "", "icon": "play-circle", "x": 175, "y": 60, "width": 50, "height": 50 }, { "type": "freedom", "nodeName": "待審批", "id": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "node_code": "待審批", "trigger_event": "", "branch_flow": "", "icon": "sync", "x": 330, "y": 160, "width": 50, "height": 120 }, { "type": "end", "nodeName": "已通過", "id": "end-JjRvtD5J2GIJKCn8MF7IYwxh00000999", "node_code": "已通過", "trigger_event": "", "branch_flow": "", "icon": "stop", "x": 330, "y": 360, "width": 50, "height": 50 }, { "type": "end", "nodeName": "審批拒絕", "id": "end-J1DMScH5YjSKyk0HeNkbt62F00010001", "node_code": "審批拒絕", "trigger_event": "", "branch_flow": "", "icon": "stop", "x": 500, "y": 350, "width": 50, "height": 50 } ], "linkList": [ { "type": "link", "id": "link-BpI6ZuX1bJywz5SEi3R5QaWoi7g3QiSr", "sourceId": "start-HiXWf8wsAcrWXjAAXVWc6AQk00000001", "targetId": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "label": "LINE000000", "role": [], "organize": [], "audit_role": [], "audit_organize": [], "audit_organize_same": "0", "audit_dealer_same": "0", "audit_dealers": [], "notice": "0", "plug": "", "pass_option": "pass", "row_par_json": "", "judge_fields": "", "auth_at": "", "auth_user": "", "auth_stat": "", "auth_mark": "", "cls": { "linkType": "Flowchart", "linkColor": "#008000", "linkThickness": 4 } }, { "type": "link", "id": "link-5xJWzGlkIpUCsjmpfgesJxAOMHwkPlno", "sourceId": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "targetId": "end-J1DMScH5YjSKyk0HeNkbt62F00010001", "label": "LINE000001", "role": [], "organize": [], "audit_role": [ "PROJECT_SUPPORT_PLAN_CODE" ], "audit_organize": [], "audit_organize_same": "0", "audit_dealer_same": "0", "audit_dealers": [], "notice": "0", "plug": "", "pass_option": "reject", "row_par_json": "", "judge_fields": "", "auth_at": "", "auth_user": "", "auth_stat": "", "auth_mark": "", "cls": { "linkType": "Flowchart", "linkColor": "#808080", "linkThickness": 1 } }, { "type": "link", "id": "link-g05V3usXa86wAtpcMkvGzybdBlpasMjU", "sourceId": "freedom-YakFJzZ5VSp3Gec6ZULD2JDK00000004", "targetId": "end-JjRvtD5J2GIJKCn8MF7IYwxh00000999", "label": "LINE000002", "role": [], "organize": [], "audit_role": [ "PROJECT_SUPPORT_PLAN_CODE" ], "audit_organize": [], "audit_organize_same": "0", "audit_dealer_same": "0", "audit_dealers": [], "notice": "0", "plug": "", "pass_option": "approve", "row_par_json": "", "judge_fields": "", "auth_at": "", "auth_user": "", "auth_stat": "", "auth_mark": "", "cls": { "linkType": "Flowchart", "linkColor": "#808080", "linkThickness": 1 } } ] } }
關于“vue+jsplumb實現工作流程圖的方法”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。