赞
踩
jsplumb + vue2
需求分析:两个表格分别展示需要拼接的数据,通过拖拽连线建立数据绑定关系。
实现步骤:
一、渲染表格数据
二、初始化节点数据
三、绑定事件
四、获取链接关系数据
1、根据已有数据初始化连线关系
2、新增数据不改变原连线添加节点
五、优化功能三:数据量大,表格滚动,滚动时连线跟随移动
#一、渲染数据
根据你的数据渲染出表格,注意绑定唯一字段,jsplumb使用
<template> <div class="app-container"> <el-row id="container" :gutter="20"> <el-col :span="11"> <div id="leftTable" style="display: inline-block"> <div style="text-indent: 0px; font-size: 16px;text-align: center;margin-bottom:5px">数据对象</div> <table style="height: 535px; overflow: scroll; display: inline-block" @scroll="connect"> <thead> <tr> <th v-for="col in sourceColumn" :key="col.dataIndex" style=" text-align: left" :style="{minWidth:col.width}" > {{ col.title }} </th> </tr> </thead> <tbody> <tr style="overflow:hidden;" v-for="code in sourceList" :id="code[sourceKey]" :key="code" name="joint" > <td v-for="col in sourceColumn" :key="index + col.dataIndex" style="text-align: left;" :style="{ textIndent: col.dataIndex == sourceKey ? code.indent * 20 + 'px' : '0px', minWidth:col.width, }" > {{ code[col.dataIndex] }} </td> <span v-if="code.data_type != 'Object' && code.data_type != 'Array' && !code.disabled && code.dict_type" style=" display: inline-block; width: 14px; height: 14px; border-radius: 50%; background: #ccc; margin-left: -15px; transform: translateY(5px); " :style="{transform:'translateY('+code.top + ')'}" > </span> </tr> </tbody> </table> </div> </el-col> <el-col :span="12" :offset="1"> <div id="rightTable" style=" height: 555px; overflow-y: auto; display: inline-block; position: relative; padding-left: 50px; " @scroll="connect" > <div v-for="target in targetList" :key="target.title" style="position: relative; margin-bottom: 10px" > <div style="text-indent: 15px; font-size: 16px;text-align: center;margin-bottom:5px"> {{ target.title }} </div> <table style="margin-left: 15px"> <thead style="width: 100%"> <tr> <th v-for="col in targetColumn" :key="col.dataIndex" style=" min-width: 180px; text-align: left; text-indent: 40px; " > {{ col.title }} </th> </tr> </thead> <tbody style="width: 100%"> <tr v-for="(data, index) in target.list" :key="index" :id="'right' + (data[targetKey] ? data[targetKey] : data)" name="data" style="position: relative" > <td style="text-align: left; text-indent: 40px" v-for="col in targetColumn" :key="index + col.dataIndex" > {{ data[col.dataIndex] }} </td> <span style=" display: inline-block; width: 14px; height: 14px; border-radius: 50%; background: #ccc; margin-top: 5px; margin-left: -0px; position: absolute; left: 0; top: 0; z-index: 999; " ></span> </tr> </tbody> </table> </div> <div v-if="targetList.length == 0" style=" color: #ffffff88; text-align: center; font-size: 14px; margin-top: 80px; " > 请选择字典 </div> </div> </el-col> </el-row> </div> </template>
#二、初始化数据节点
<script> //局部引入 import jsPlumb from "jsplumb"; //jsplumb使用 let $jsPlumb = jsPlumb.jsPlumb; let jsPlumb_instance = null; // 缓存实例化的jsplumb对象 export default { data() { return { // 左侧对照数据 // sourceList: [ // { name: "表字段1" }, // { name: "表字段2" }, // { name: "表字段3" } // ], // 右侧标准字典数据 // targetList: [ // { name: "表字段1" }, // { name: "字段2" }, // { name: "字段3" }, // { name: "字段4" } // ], pointList: null, //向后端传递的map映射关系 diffList: [], count: 0 }; }, props: [ "sourceList", "targetList", "targetColumn", "targetKey", "sourceColumn", "sourceKey" ], mounted() { setTimeout(() => { this.showPlumb(); }, 100); }, watch: { targetList(newval, oldval) { let oldList = oldval.map((val) => val.title); this.diffList = newval.filter((val) => !oldList.includes(val.title)); setTimeout(() => { this.showDiff(); }, 100); } }, methods: { showPlumb() { let self = this; // 清除端点、连接 jsPlumb_instance?.reset(); this.pointList = new Map(); this.$forceUpdate(); jsPlumb_instance = $jsPlumb.getInstance({ Container: "container", // 选择器id EndpointStyle: { radius: 0.11, fill: "#00c1de" }, // 端点样式 PaintStyle: { stroke: "#00c1de", strokeWidth: 4 }, // 绘画样式,默认8px线宽 #456 HoverPaintStyle: { stroke: "#1E90FF" }, // 默认悬停样式 默认为null ConnectionOverlays: [ // 此处可以设置所有箭头的样式,因为我们要改变连接线的样式,故单独配置 // Arrow-箭头 Label-标签 PlainArrow-平头箭头 Diamond-菱形 Diamond(钻石)-钻石箭头 Custom-自定义 // [ // "Arrow", // { // // 设置参数可以参考中文文档 // location: 1, // length: 8, // paintStyle: { // // stroke: "#409EFF", // // fill: "#409EFF" // fill: '#7AB02C', // radius: 10 // } // } // ] ], Connector: ["Straight"], // 连接器的类型:直线Straight,流程图flowchart,状态机state machine,贝塞尔曲线Bezier等 默认贝塞尔曲线 DrapOptions: { cursor: "crosshair", zIndex: 2000 } // connectorStyle:{ // paintStyle: { // fill: '#7AB02C', // radius: 10 // }, // } }); //调用初始化节点 jsPlumb_instance.batch(() => { for (let i = 0; i < this.sourceList.length; i++) { //根据条件筛选哪些数据可以连接 if ( this.sourceList[i].data_type != "Object" && this.sourceList[i].data_type != "Array" && !this.sourceList[i].disabled && this.sourceList[i].dict_type ) { this.initLeaf(this.sourceList[i][this.sourceKey], "joint"); } } for (let j = 0; j < this.targetList.length; j++) { for (let i = 0; i < this.targetList[j].list.length; i++) { this.initLeaf( "right" + (this.targetList[j].list[i][this.targetKey] ? this.targetList[j].list[i][this.targetKey] : this.targetList[j].list[i]), "data" ); } } }); const joint = document.getElementsByName("joint"); const data = document.getElementsByName("data"); jsPlumb_instance.setSourceEnabled(joint, true); jsPlumb_instance.setTargetEnabled(data, true); jsPlumb_instance.setDraggable(joint, true); // 是否支持拖拽 jsPlumb_instance.setDraggable(data, true); // 是否支持拖拽 jsPlumb_instance.bind("dblclick", (conn, originalEvent) => { // this.$confirm("确认删除映射么?", "提示", { // confirmButtonText: "确定", // cancelButtonText: "取消", // closeOnClickModal: false, // type: "warning" // }) // .then(() => { jsPlumb_instance.deleteConnection(conn); // }) // .catch(() => {}); }); ///两个表进行关联时 连线 jsPlumb_instance.bind("connection", function (info) { //连线发盛变化时,处理自己需要的数据 self.pointList.set(info.sourceId, info.targetId.split("right")[1]); self.$emit("change", self.pointList); }); // 删除连线 jsPlumb_instance.bind("connectionDetached", function (evt) { if (self.pointList.has(evt.sourceId)) { self.pointList.delete(evt.sourceId); self.$emit("change", self.pointList); } }); }, // 初始化具体节点 initLeaf(key, type) { const ins = jsPlumb_instance; const elem = document.getElementById(key); // console.log(key, elem, 99); if (type == "joint") { ins.makeSource(elem, { anchor: [1, 0.5, 0, 0], // 左 上 右 下 allowLoopback: false, maxConnections: 1, endpoint: "Dot" }); } else { ins.makeTarget(elem, { anchor: [0, 0.5, 0, 0], allowLoopback: false, maxConnections: 100 // endpoint: "Dot", // paintStyle: { // fill: "blue", // strokeWidth: 1 // } }); } }, initLeft() { for (let i = 0; i < this.sourceList.length; i++) { if ( this.sourceList[i].data_type != "Object" && this.sourceList[i].data_type != "Array" ) { this.initLeaf(this.sourceList[i][this.sourceKey], "joint"); } } } } }; </script>
我这里用的props的数据,可以用自己的数据,注意数据结构即可
绑定事件上面方法以实现
#四、初始化已有的连接数据及右侧数据变化时将节点渲染为可连接节点
// 初始化字典连线
initLines () {
this.sourceList.forEach(item => {
if(item.dict_data){
console.log("right" + item.dict_data_path + "__" + item.dict_data + "__" +item.dict_data_type);
jsPlumb_instance.connect({
source: item[this.sourceKey],
target:"right" + item.dict_data_path + "__" + item.dict_data + "__" +item.data_type
});
}
})
},
遍历需要连接的数据,调用实例的connect方法连接
watch: { targetList(newval, oldval) { let oldList = oldval.map((val) => val.title); this.diffList = newval.filter((val) => !oldList.includes(val.title)); setTimeout(() => { this.showDiff(); }, 100); } }, methods: { showDiff() { for (let j = 0; j < this.diffList.length; j++) { for (let i = 0; i < this.diffList[j].list.length; i++) { this.initLeaf( "right" + (this.diffList[j].list[i][this.targetKey] ? this.diffList[j].list[i][this.targetKey] : this.diffList[j].list[i]), "data" ); } } }, }
监听数据变化,将新增的数据渲染节点
#五、页面滚动,连线跟随变化
触发滚动事件时,将现有的连接关系保存,将原有的连线删除,重新简历连线,这里设置滚动三次触发一次方法
connect() { this.count++; if (this.count >= 3) { let connections = jsPlumb_instance.getAllConnections(); let linePoints = []; for (let i = connections.length - 1; i >= 0; i--) { linePoints.push([connections[i].sourceId, connections[i].targetId]); jsPlumb_instance.deleteConnection(connections[i]); } for (let i = 0; i < linePoints.length; i++) { jsPlumb_instance.connect({ source: linePoints[i][0], target: linePoints[i][1] }); } this.count = 0; } },
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。