业务逻辑,类似与navcat中的视图可视化的操作 拖动列表 生成表格并支持连线

展示效果

​​​​

    <el-row><el-col :span="4"><draggablev-model="tableData"@end="onEnd":group="{ name: 'test', pull: 'clone', put: 'false' }":sort="false"@start="startDra"><div v-for="(element, index) in tableData" :key="index">{{ element.name }}</div></draggable></el-col><el-col :span="12"><draggabledraggablestyle="height: 100vh; position: relative"v-model="tableData2":group="{ name: 'test', pull: '' }"@add="addList"id="container"><div v-for="(element, index) in tableData2" :key="index"><divclass="chatBox fx-d-c"v-drag:id="element.name + '_' + element.node"><div class="topBar fx-a-c"><div class="flex1 fx-a-c drayView" style="width: 100%"><span class="chatName">{{ element.name }}</span></div><iclass="el-icon-edit"style="margin-right: 10px;height: 55px;width: 30px;line-height: 55px;cursor: pointer;"@click="closeChatBox($event)"></i></div><ul><liv-for="(item, index) in element.list":key="'left' + index":id="item.id"name="source"class="lines">{{ item.name }}</li></ul></div></div></draggable></el-col></el-row>

vue 自定义的可拖拽组件

import Vue from 'vue';
Vue.directive('drag', function (el, binding, vnode, oldVnode) {const dialogHeaderEl = el.querySelector('.drayView');// 监听 当前绑定指令元素的鼠标点下去的事件dialogHeaderEl.onmousedown = function (e) {const { ox, oy } = {ox: e.clientX - el.offsetLeft,oy: e.clientY - el.offsetTop,};let fit = false;let clear = true;// 监听鼠标来回移动的事件document.onmousemove = function (em) {const { left, top } = {left: em.clientX - ox,top: em.clientY - oy,};if ((left != 0 || top != 0) && clear) {vnode.context.clearLine();clear = false;}// ;// 将鼠标 换成小手el.style.cursor = 'pointer';// 和盒子的定位 改变left 和 top的值el.style.left = left + 'px';el.style.top = top + 'px';};// 监听鼠标抬起的事件document.onmouseup = function (eu) {document.onmousemove = null;if (!fit) {fit = true;vnode.context.ConnectLine();}el.style.cursor = 'default';};};
});

数据源的准备工作

 tableData: [{date: '2016-05-02',name: '王涛',province: '上海',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333,node: '1',tag: '家',list: [{ id: 1, name: 123 },{ id: 7, name: 'wt' },],},{date: '2016-05-04',name: '王涛2',province: '上海',node: '2',city: '普陀区',address: '上海市普陀区金沙江路 1517 弄',zip: 200333,list: [{ id: 2, name: 23 }],tag: '公司',},{date: '2016-05-01',name: '王涛3',province: '上海',node: '3',city: '普陀区',address: '上海市普陀区金沙江路 1519 弄',zip: 200333,tag: '家',list: [{ id: 3, name: 1023 }],},{date: '2016-05-03',name: '王涛4',province: '上海',node: '4',city: '普陀区',address: '上海市普陀区金沙江路 1516 弄',zip: 200333,tag: '公司',list: [{ id: 4, name: 1034 }],},],readyList: [],tableData2: [{date: '2016-05-02',name: '王涛',province: '上海',node: '10',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333,list: [{ id: 5, name: '男' },{ id: 6, name: '我是老六' },],tag: '家',},],

初始化方法以及一些连线的方法

    showPlumb() {this.jsPlumb = this.$jsPlumb.getInstance({Container: 'container', // 选择器idEndpointStyle: { radius: 0.11, fill: '#999' }, // 端点样式PaintStyle: { stroke: '#999', strokeWidth: 2 }, // 绘画样式,默认8px线宽  #456HoverPaintStyle: { stroke: '#994B0A', strokeWidth: 3 }, // 默认悬停样式  默认为nullConnectionOverlays: [// 此处可以设置所有箭头的样式['Arrow',{// 设置参数可以参考中文文档location: 1,length: 12,paintStyle: {stroke: '#999',fill: '#999',},},],],Connector: ['Straight'], // 要使用的默认连接器的类型:直线,折线,曲线等DrapOptions: { cursor: 'crosshair', zIndex: 2000 },});this.jsPlumb.batch(() => {this.tableData2.forEach((element, index) => {element.list.forEach((list, i) => {this.initLeaf('ids' + this.tableData2[index].list[i].id, 'source');this.initLeaf('ids' + this.tableData2[index].list[i].id, 'target');});});});this.setjsPlumb(true, true);this.ConnectLine();//点击连线this.jsPlumb.bind('click', (conn, originalEvent) => {this.LinkData.forEach((element, index) => {if (element.sourceId == conn.sourceId &&element.targetId == conn.targetId) {this.LinkData.splice(index, 1);}});this.jsPlumb.deleteConnection(conn);});//连线时触发this.jsPlumb.bind('connection', (conn, originalEvent) => {let obj = {sourceId: conn.sourceId,targetId: conn.targetId,};this.LinkData.push(obj);this.readyList = JSON.parse(JSON.stringify(this.LinkData));this.LinkData = this.readyList.reduce((curr, next) => {/*判断对象中是否已经有该属性  没有的话 push 到 curr数组*/obj[next.sourceId + next.targetId]? '': (obj[next.sourceId + next.targetId] = curr.push(next));return curr;}, []);});//右键触发this.jsPlumb.bind('contextmenu', (conn, originalEvent) => {});},startDra() {this.jsPlumb.deleteEveryConnection();this.jsPlumb.deleteEveryEndpoint();},initLeaf(id, type) {const ins = this.jsPlumb;const elem = document.getElementById(id);if (type === 'source') {ins.makeSource(elem, {anchor: [1, 0.5, 0, 0], // 左 上 右 下allowLoopback: false, //允许回连maxConnections: -1, //最大连接数(-1表示不限制)});} else {ins.makeTarget(elem, {anchor: [0, 0.5, 0, 0],allowLoopback: false,maxConnections: -1,});}},//初始化连接线ConnectLine() {let allArr = [];for (var i = 0; i < this.LinkData.length; i++) {var flag = true;for (var j = 0; j < allArr.length; j++) {if (this.LinkData[i].targetId == allArr[j].targetId &&this.LinkData[i].sourceId == allArr[j].sourceId) {flag = false;}}if (flag) {allArr.push(this.LinkData[i]);}}setTimeout(() => {for (const item of allArr) {this.jsPlumb.connect({source: item.sourceId,target: item.targetId,});}}, 0);},

完整代码

<template><div><el-row><el-col :span="4"><draggablev-model="tableData"@end="onEnd":group="{ name: 'test', pull: 'clone', put: 'false' }":sort="false"@start="startDra"><div v-for="(element, index) in tableData" :key="index">{{ element.name }}</div></draggable></el-col><el-col :span="12"><draggabledraggablestyle="height: 100vh; position: relative"v-model="tableData2":group="{ name: 'test', pull: '' }"@add="addList"id="container"><div v-for="(element, index) in tableData2" :key="index"><div class="chatBox fx-d-c" v-drag :id="'element_' + element.node"><div class="topBar fx-a-c"><div class="flex1 fx-a-c drayView" style="width: 100%"><span class="chatName">{{ element.name }}</span></div><iclass="el-icon-edit"style="margin-right: 10px;height: 55px;width: 30px;line-height: 55px;cursor: pointer;"@click="closeChatBox($event, element)"></i></div><ul><liv-for="(item, index) in element.list":key="'left' + index":id="'ids' + item.id"name="source"class="lines">{{ item.name }}</li></ul></div></div></draggable></el-col></el-row></div>
</template><script>
import Vue from 'vue';
Vue.directive('drag', function (el, binding, vnode, oldVnode) {const dialogHeaderEl = el.querySelector('.drayView');// 监听 当前绑定指令元素的鼠标点下去的事件dialogHeaderEl.onmousedown = function (e) {const { ox, oy } = {ox: e.clientX - el.offsetLeft,oy: e.clientY - el.offsetTop,};let fit = false;let clear = true;// 监听鼠标来回移动的事件document.onmousemove = function (em) {const { left, top } = {left: em.clientX - ox,top: em.clientY - oy,};if ((left != 0 || top != 0) && clear) {vnode.context.clearLine();clear = false;}// ;// 将鼠标 换成小手el.style.cursor = 'pointer';// 和盒子的定位 改变left 和 top的值el.style.left = left + 'px';el.style.top = top + 'px';};// 监听鼠标抬起的事件document.onmouseup = function (eu) {document.onmousemove = null;if (!fit) {fit = true;vnode.context.ConnectLine();}el.style.cursor = 'default';};};
});
export default {data() {return {jsPlumb: null,//初始的idLinkData: [],tableData: [{date: '2016-05-02',name: '王涛',province: '上海',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333,node: '1',tag: '家',list: [{ id: 1, name: 123 },{ id: 7, name: 'wt' },],},{date: '2016-05-04',name: '王涛2',province: '上海',node: '2',city: '普陀区',address: '上海市普陀区金沙江路 1517 弄',zip: 200333,list: [{ id: 2, name: 23 }],tag: '公司',},{date: '2016-05-01',name: '王涛3',province: '上海',node: '3',city: '普陀区',address: '上海市普陀区金沙江路 1519 弄',zip: 200333,tag: '家',list: [{ id: 3, name: 1023 }],},{date: '2016-05-03',name: '王涛4',province: '上海',node: '4',city: '普陀区',address: '上海市普陀区金沙江路 1516 弄',zip: 200333,tag: '公司',list: [{ id: 4, name: 1034 }],},],readyList: [],tableData2: [{date: '2016-05-02',name: '王涛',province: '上海',node: '10',city: '普陀区',address: '上海市普陀区金沙江路 1518 弄',zip: 200333,list: [{ id: 5, name: '男' },{ id: 6, name: '我是老六' },],tag: '家',},],};},mounted() {this.$nextTick(() => {this.showPlumb();});},methods: {showPlumb() {this.jsPlumb = this.$jsPlumb.getInstance({Container: 'container', // 选择器idEndpointStyle: { radius: 0.11, fill: '#999' }, // 端点样式PaintStyle: { stroke: '#999', strokeWidth: 2 }, // 绘画样式,默认8px线宽  #456HoverPaintStyle: { stroke: '#994B0A', strokeWidth: 3 }, // 默认悬停样式  默认为nullConnectionOverlays: [// 此处可以设置所有箭头的样式['Arrow',{// 设置参数可以参考中文文档location: 1,length: 12,paintStyle: {stroke: '#999',fill: '#999',},},],],Connector: ['Straight'], // 要使用的默认连接器的类型:直线,折线,曲线等DrapOptions: { cursor: 'crosshair', zIndex: 2000 },});this.jsPlumb.batch(() => {this.tableData2.forEach((element, index) => {element.list.forEach((list, i) => {this.initLeaf('ids' + this.tableData2[index].list[i].id, 'source');this.initLeaf('ids' + this.tableData2[index].list[i].id, 'target');});});});this.setjsPlumb(true, true);this.ConnectLine();//点击连线this.jsPlumb.bind('click', (conn, originalEvent) => {this.LinkData.forEach((element, index) => {if (element.sourceId == conn.sourceId &&element.targetId == conn.targetId) {this.LinkData.splice(index, 1);}});this.jsPlumb.deleteConnection(conn);});//连线时触发this.jsPlumb.bind('connection', (conn, originalEvent) => {let obj = {sourceId: conn.sourceId,targetId: conn.targetId,};this.LinkData.push(obj);this.readyList = JSON.parse(JSON.stringify(this.LinkData));this.LinkData = this.readyList.reduce((curr, next) => {/*判断对象中是否已经有该属性  没有的话 push 到 curr数组*/obj[next.sourceId + next.targetId]? '': (obj[next.sourceId + next.targetId] = curr.push(next));return curr;}, []);});//右键触发this.jsPlumb.bind('contextmenu', (conn, originalEvent) => {});},startDra() {this.jsPlumb.deleteEveryConnection();this.jsPlumb.deleteEveryEndpoint();},initLeaf(id, type) {const ins = this.jsPlumb;const elem = document.getElementById(id);if (type === 'source') {ins.makeSource(elem, {anchor: [1, 0.5, 0, 0], // 左 上 右 下allowLoopback: false, //允许回连maxConnections: -1, //最大连接数(-1表示不限制)});} else {ins.makeTarget(elem, {anchor: [0, 0.5, 0, 0],allowLoopback: false,maxConnections: -1,});}},//初始化连接线ConnectLine() {let allArr = [];for (var i = 0; i < this.LinkData.length; i++) {var flag = true;for (var j = 0; j < allArr.length; j++) {if (this.LinkData[i].targetId == allArr[j].targetId &&this.LinkData[i].sourceId == allArr[j].sourceId) {flag = false;}}if (flag) {allArr.push(this.LinkData[i]);}}setTimeout(() => {for (const item of allArr) {this.jsPlumb.connect({source: item.sourceId,target: item.targetId,});}}, 0);},clearLine() {this.jsPlumb.deleteEveryConnection();this.jsPlumb.deleteEveryEndpoint();this.jsPlumb.setSuspendDrawing(false, true);},setjsPlumb(sourceFlag, targetFlag) {const source = document.getElementsByName('source');const target = document.getElementsByName('target');this.jsPlumb.setSourceEnabled(source, sourceFlag);this.jsPlumb.setTargetEnabled(target, targetFlag);this.jsPlumb.setDraggable(source, false); // 是否支持拖拽this.jsPlumb.setDraggable(target, false); // 是否支持拖拽},closeChatBox(e, row) {let node = e.currentTarget.parentNode.parentNode;let b = e.currentTarget.parentNode.parentNode.getElementsByTagName('li');//深拷贝防止数组变化const allLines = [...this.jsPlumb.getConnections()];const LinkData = [...this.LinkData];for (const iterator of b) {allLines.forEach((element, index) => {if (iterator.id == element.sourceId ||iterator.id == element.targetId)this.jsPlumb.deleteConnection(element);});this.LinkData = LinkData.filter(item => {return iterator.id !== item.sourceId && iterator.id !== item.targetId;});}node.remove();row.isDel = 1;this.$forceUpdate();this.ConnectLine();},onEnd(e) {// console.log(e, '11111111');},addList(e) {e.item._underlying_vm_.list.forEach((list, i) => {this.initLeaf('ids' + list.id, 'source');this.initLeaf('ids' + list.id, 'target');});this.ConnectLine();},},
};
</script>
<style lang="less" scoped>
.chatBox {//不能用fixed 不然会出现错乱position: absolute;width: 150px;height: 300px;right: 130px;top: 384px;// z-index: 1;background: white;box-shadow: 0px 1px 6px 0px rgba(0, 21, 41, 0.12);.topBar {width: 150px;height: 56px;display: flex;line-height: 56px;box-shadow: 0px 1px 6px 0px rgba(0, 21, 41, 0.12);z-index: 10;cursor: move;}.chatAvatar {width: 36px;height: 36px;overflow: hidden;margin-left: 10px;object-fit: cover;}.chatName {width: 50px;margin-left: 12px;font-size: 16px;font-weight: 600;color: #333333;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.chatContent {padding: 8px 0;overflow-y: auto;overflow-x: hidden;}
}
.flex1 {display: flex;
}
.el-icon-edit {z-index: 100;
}
</style>

vue+draggable +jsPlumb 表格数据连线相关推荐

  1. vue实现导入表格数据【纯前端实现】

    一.文章引导 #mermaid-svg-j9HOnISPE2Hyb9Zj {font-family:"trebuchet ms",verdana,arial,sans-serif; ...

  2. Vue+element-ui实现表格数据渲染+分页

    Vue+element-ui实现表格数据渲染+分页 具体属性请看官方文档:Table 表格 这里给大家看一个比较不错的表格数据渲染的例子,也是我目前所写的项目中的一部分. 这里呢我们就不给大家说顶栏和 ...

  3. vue+elementui查询表格数据页面卡死问题

    一 问题描述 vue+elementui项目,本地idea启动,功能测试没问题,部署到tomcat服务器,查询表格数据,正确返回后,页面卡死. 浏览器console栏有vue warn信息:you m ...

  4. vue读取excel表格数据_vue 利用 js-xslx 读取 excel 表格文件

    文件读取~~~ 表格数据 excel读取数据.jpg // template // 文件选择,或者使用原生 imput type 为 file action="/" :on-cha ...

  5. vue实现导出表格数据

    先看实现效果 1.安装依赖 cnpm install -S file-saver xlsx cnpm install -S script-loader 2.在公共组件中引入 import XLSX f ...

  6. vue多个表格数据合并导出excel(sheetjs或exceljs)

    最近公司有个需求每周要查看一次数据统计,页面有个四个表格内容 要求把四个表格的数据导出到一个excel里面,查了一下网上的导出excel方法,但都没有要把多个导出成一个excel的例子. 不过经过一番 ...

  7. vue项目 element表格数据行转列数据互转

    后台返回的格式一个人名里面带有这个人的所有信息,我们需要数据转化 ( 俗称行转列 ) 这个平时可以用在时间日期上比较多,这个案例只是把这个写法记录下来 <template><div ...

  8. vue表格里的html怎么,vue如何提交表格数据?

    html tr渲染用v-for boxnewrankdesctitle {{v.box}}{{v.new}}{{v.rank}}{{v.title}} 提交 js 从后台获取的数据 tabData t ...

  9. Vue+ElementUI纯前端技术实现对表格数据的增删改查

    Vue+ElementUI纯前端技术实现对表格数据的增删改查 页面展示效果 一.页面结构 分为三个部分 head body 以及script 一般我个人是在head中引入一些组件库 , 还有一些样式 ...

最新文章

  1. Ubuntu 想要更新源 报错 “E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用)”
  2. 只改一个值!马上加快宽带上网速度
  3. java b kb mb gb 转换_java 上传文件大小转换为 GB/MB/KB/B
  4. java 定义类变量初始化吗_Java的变量有哪些类型?变量如何定义?如何初始化?请说明理由并举例_学小易找答案...
  5. python时间倒计时显示屏厂家_python 实现倒计时功能(gui界面)
  6. 3D游戏建模就是那么简单
  7. 错误代码666020_Windows 系统错误代码大全
  8. 小白用python处理excel文件-python高手之路python处理excel文件(方法汇总)
  9. linux 内核源码学习
  10. 使用TF卡烧录Jetson NX开发板
  11. 谷歌宣布退出中国 google.cn已经关闭
  12. 网上申请办理杭州市民卡
  13. 思维拓展:用java实现巧妙过桥问题
  14. DEV01-GBase 8a MPP Cluster SQL 编码进阶篇
  15. java利用UUID类生成随机数
  16. 基于SRGAN的图像超分辨率处理
  17. WinHttp.WinHttpRequest.5.1
  18. 1414,成绩(C++一本通评测系统)
  19. David P.Williams论文系列 基于间隙度的声呐图像快速无监督海底特征描述
  20. MSSQL Server查询优化方法

热门文章

  1. JAVA-IDEA开发10个小手段
  2. linux iio 设备驱动,Linux设备驱动之IIO子系统——IIO框架数据读取
  3. STM32MP157驱动开发——Linux IIO驱动(上)
  4. C:/Inetpub/AdminsScripts的常用语法
  5. c#:list转datatable;xtraReport打印
  6. 0.10版本后的kafka配置producer和comsumer的server参数
  7. opc服务器连接plc断开显示,如何判断OPC与PLC通讯失败
  8. 仍是在思过崖攀爬的人
  9. java 句柄无效_Java开发网 - java.io.IOException: 句柄无效???
  10. Spring前一次定时任务没执行完,下次任务是否会执行