vue中el-table和jsplumb實現(xiàn)連線功能
前言
最近在開發(fā)中遇到了一個需求,是將兩組樹形結(jié)構(gòu)的數(shù)據(jù)通過連線進行關(guān)聯(lián)映射。what?連線功能?還是兩組樹形結(jié)構(gòu)???讓我頭疼的并非連線而是對樹形結(jié)構(gòu)的展示,我需要一個能夠清晰的展示樹形結(jié)構(gòu)的關(guān)系和每條數(shù)據(jù)里的詳細數(shù)據(jù)的組件,就這樣el-table走進了我的視野里。
準備工作
所用插件: "element-plus" + "jsplumb"npm install 就完事
第一步: 定義靜態(tài)數(shù)據(jù)并顯示table組件
新建一個line.vue
文件,定義一個id為container
的div標簽,在這個標簽內(nèi)放入兩個el-table,并根據(jù)定義的靜態(tài)數(shù)據(jù)進行基礎(chǔ)的配置。需要注意的是el-table當(dāng) row 中包含 children
字段時,被視為樹形數(shù)據(jù)。 渲染嵌套數(shù)據(jù)需要 prop 的 row-key
。具體見下面代碼:
<template> <div class="line"> <div id="container" style="display: flex; justify-content: space-between; position: relative"> <el-table ref="leftTable" :data="leftTreeData" style="width: 40%; margin-bottom: 20px; display: inline-block;" row-key="id" border default-expand-all > <el-table-column prop="name" label="姓名"/> <el-table-column prop="gender" label="性別"/> <el-table-column prop="age" label="年齡"/> </el-table> <el-table ref="rightTable" :data="rightTreeData" style="width: 40%; margin-bottom: 20px; display: inline-block;" row-key="id" border default-expand-all > <el-table-column prop="name" label="姓名"/> <el-table-column prop="gender" label="性別"/> <el-table-column prop="age" label="年齡"/> </el-table> </div> </div> </template> <script setup> import { ref } from 'vue' // 左側(cè)靜態(tài)數(shù)據(jù) const leftData = ref([ {id: 1, name: '張三', gender: '男', age: 23, parentId: null, hasChild: true}, {id: 2, name: '李四', gender: '男', age: 22, parentId: null, hasChild: false}, {id: 3, name: '坤坤', gender: '女', age: 24, parentId: 1, hasChild: true}, {id: 4, name: '小黑子', gender: '男', age: 25, parentId: 3, hasChild: false}, ]); const leftTreeData = ref([ { id: 1, name: '張三', gender: '男', age: 23, parentId: null, children: [ {id: 3, name: '坤坤', gender: '女', age: 24, parentId: 1, children: [ {id: 4, name: '小黑子', gender: '男', age: 25, parentId: 3}, ] }, ] }, {id: 2, name: '李四', gender: '男', age: 22, parentId: null}, ]); // 右側(cè)靜態(tài)數(shù)據(jù) const rightData = ref([ {id: 5, name: '柯潔', gender: '男', age: 23, parentId: null, hasChild: true}, {id: 6, name: '戰(zhàn)鷹', gender: '女', age: 30, parentId: 5, hasChild: false}, {id: 7, name: '唱跳', gender: '男', age: 24, parentId: null, hasChild: false}, {id: 8, name: 'rap', gender: '男', age: 25, parentId: null, hasChild: false}, ]); const rightTreeData = ref([ {id: 5, name: '柯潔', gender: '男', age: 23, parentId: null, children: [ {id: 6, name: '戰(zhàn)鷹', gender: '女', age: 30, parentId: 6}, ] }, {id: 7, name: '唱跳', gender: '男', age: 24, parentId: null}, {id: 8, name: 'rap', gender: '男', age: 25, parentId: null}, ]); const leftTable = ref(null); const rightTable = ref(null); </script>
第二步: 初始化jsPlumb并設(shè)置可以連線的元素
引入jsplumb 并創(chuàng)建jsplumb實例,實例中大部分的配置主要是對箭頭的樣式配置,具體參數(shù)信息可以查看官網(wǎng)。
import { jsPlumb } from 'jsplumb' let instance = null; function init() { instance = jsPlumb.getInstance({ Connector: "Straight", //連接線形狀 Bezier: 貝塞爾曲線 Flowchart: 具有90度轉(zhuǎn)折點的流程線 StateMachine: 狀態(tài)機 Straight: 直線 PaintStyle: { strokeWidth: 3, stroke: "#dfbee7" }, //連接線樣式 Endpoint: ["Blank", { radius: 1 }], //端點 anchor: 'Right', // 繪制箭頭 Overlays: [['Arrow', { width: 12, length: 12, location: 1 }]], EndpointStyle: { fill: "#000000" }, //端點樣式 Container: "container", //目標容器id ListStyle: { endpoint: ["Rectangle", { width: 30, height: 30 }], }, }); }
由于業(yè)務(wù)的需求是只能從左側(cè)的數(shù)據(jù)連接到右側(cè)的數(shù)據(jù),并且有子項的那一行不能進行連接操作,所以我這邊要將左側(cè)的每行數(shù)據(jù)設(shè)置為起點右側(cè)為終點并過濾那些有子項的行,而設(shè)置起點和終點需要拿到對應(yīng)的元素或者標識,這時我們就需要給el-table
的row
設(shè)置class名
<template> <div class="line"> <div id="container" style="display: flex; justify-content: space-between; position: relative"> <el-table ref="leftTable" :data="leftTreeData" :row-class-name="({row}) => `leftRow Id-${row.id}`" style="width: 40%; margin-bottom: 20px; display: inline-block;" row-key="id" border default-expand-all > <el-table-column prop="name" label="姓名"/> <el-table-column prop="gender" label="性別"/> <el-table-column prop="age" label="年齡"/> </el-table> <el-table ref="rightTable" :data="rightTreeData" :row-class-name="({row}) => `rightRow Id-${row.id}`" style="width: 40%; margin-bottom: 20px; display: inline-block;" row-key="id" border default-expand-all > <el-table-column prop="name" label="姓名"/> <el-table-column prop="gender" label="性別"/> <el-table-column prop="age" label="年齡"/> </el-table> </div> </div> </template>
我這里設(shè)置了兩個類名 leftRow
和 rightRow
來區(qū)分他是左側(cè)還是右側(cè)的行,Id-${row.id}
作為唯一標識讓我們能獲取到某一行元素
// 設(shè)置可以連線的元素 function setContainer() { const leftElList = document.querySelectorAll('.leftRow'); // 左側(cè)行元素集合 const rightElList = document.querySelectorAll('.rightRow'); // 右側(cè)行元素集合 // 將dom元素設(shè)置為連線的起點或者終點 設(shè)置了起點的元素才能開始連線 設(shè)置為終點的元素才能為連線終點 instance.batch(function () { [leftElList, rightElList].forEach((trList, index) => { trList.forEach((tr) => { const id = interceptId(tr.classList[2]); if (index === 0) { const item = leftData.value.find(i => i.id == id); // 判斷是否有子項,若沒有則設(shè)置為起點 !item?.hasChild && instance.makeSource(tr, { allowLoopback: false, anchor: ["Right"], // 設(shè)置端點位置 maxConnections: 1 }); } else { const item = rightData.value.find(i => i.id == id); // 判斷是否有子項,若沒有則設(shè)置為終點 !item?.hasChild && instance.makeTarget(tr, { anchor: ["Left"], maxConnections: 1 }); } }); }); }); } // 截取元素類名中的id const interceptId = className => { return className.slice(className.indexOf('-') + 1); }
然后我們在onMounted
中調(diào)用這些方法就可以實現(xiàn)連線功能了
const initJsPlumb = () => { jsPlumb.ready(function () { // 初始化jsPlumb 創(chuàng)建jsPlumb實例 init(); // 設(shè)置可以為連線起點和連線終點的元素 setContainer(); }); } onMounted(() => { initJsPlumb(); })
看!成功啦!
設(shè)置默認連線和刪除連線功能
const relationship = reactive([ {sourceId: 4, targetId: 8} ]) // 設(shè)置默認連線 function setConnect(relationship) { setTimeout(() => { relationship.forEach(function (data) { // source是連線起點元素id target是連線終點元素id instance.connect({ source: document.querySelector(`.Id-${data.sourceId}`), target: document.querySelector(`.Id-${data.targetId}`) }); }); }) } // 綁定事件監(jiān)聽 function setEvent() { // 連線事件 instance.bind("connection", function (connInfo, originalEvent) { // connInfo是jsPlumb對象 可以打印出來康康有哪些東西 console.log(connInfo, originalEvent, 'connInfo') }); // 點擊連接線刪除該條線 instance.bind('click', function (connection, originalEvent) { instance.deleteConnection(connection); }) } const initJsPlumb = () => { jsPlumb.ready(function () { // 初始化jsPlumb 創(chuàng)建jsPlumb實例 init(); // 設(shè)置可以為連線起點和連線終點的元素 setContainer(); // 設(shè)置默認連線 setConnect(relationship); // 綁定事件監(jiān)聽 setEvent(); }); } onMounted(() => { initJsPlumb(); })
將上述代碼中的兩個函數(shù)一并放入到initJsPlumb
函數(shù)中執(zhí)行即可
禁用el-table的expand功能
由于數(shù)據(jù)的結(jié)構(gòu)是樹結(jié)構(gòu)所以el-table
在對含有子節(jié)點的行的最左側(cè)添加了展開
和收起
功能的一個圖標按鈕,所以當(dāng)我們點擊它收縮后會改變原有的視圖結(jié)構(gòu),而jsplumb
是用canvas
繪制的線條,它的位置并不能實時更改,所以我的解決方案是利用el-table
的expand-change
事件監(jiān)聽配合toggleRowExpansion
方法實現(xiàn)不管用戶怎么操作都是展開的狀態(tài)。
<el-table ref="leftTable" :data="leftTreeData" :row-class-name="({row}) => `leftRow Id-${row.id}`" style="width: 40%; margin-bottom: 20px; display: inline-block;" row-key="id" border default-expand-all @expand-change="(row, expanded) => !expanded && leftTable?.toggleRowExpansion(row)" > <el-table-column prop="name" label="姓名"/> <el-table-column prop="gender" label="性別"/> <el-table-column prop="age" label="年齡"/> </el-table> <el-table ref="rightTable" :data="rightTreeData" :row-class-name="({row}) => `rightRow Id-${row.id}`" style="width: 40%; margin-bottom: 20px; display: inline-block;" row-key="id" border default-expand-all @expand-change="(row, expanded) => !expanded && rightTable?.toggleRowExpansion(row)" > <el-table-column prop="name" label="姓名"/> <el-table-column prop="gender" label="性別"/> <el-table-column prop="age" label="年齡"/> </el-table>
結(jié)言
到此這篇關(guān)于el-table和jsplumb實現(xiàn)連線功能的文章就介紹到這了,更多相關(guān)el-table jsplumb連線內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解vue axios用post提交的數(shù)據(jù)格式
這篇文章主要介紹了詳解vue axios用post提交的數(shù)據(jù)格式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08Vue 頁面跳轉(zhuǎn)不用router-link的實現(xiàn)代碼
這篇文章主要介紹了 Vue 頁面跳轉(zhuǎn)不用router-link的實現(xiàn)代碼,文中給大家介紹了vue router-link跳轉(zhuǎn)傳值示例,需要的朋友可以參考下2018-04-04vue+springboot實現(xiàn)圖形驗證碼Kaptcha的示例
圖形驗證碼是做網(wǎng)站常用的功能,本文主要介紹了vue+springboot實現(xiàn)圖形驗證碼Kaptcha的示例,具有一定的參考價值,感興趣的可以了解一下2023-11-11Vue3 封裝 element-plus 圖標選擇器實現(xiàn)步驟
這篇文章主要介紹了Vue3 封裝 element-plus 圖標選擇器,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09Vue實現(xiàn)用戶沒有登陸時,訪問后自動跳轉(zhuǎn)登錄頁面的實現(xiàn)思路
這篇文章主要介紹了Vue實現(xiàn)用戶沒有登陸時,訪問后自動跳轉(zhuǎn)登錄頁面,定義路由的時候配置屬性,這里使用needLogin標記訪問頁面是否需要登錄,本文通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-02-02