jsPlumb是一个比较强大的绘图组件,它提供了一种方法,主要用于连接网页上的元素。在现代浏览器中,它使用SVG或者Canvas技术,而对于IE8以下(含IE8)的浏览器,则使用VML技术。
- 安装
npm install jsplumb --save
- main.js 引入
import jsPlumb from 'jsplumb'
Vue.prototype.$jsPlumb = jsPlumb.jsPlumb
- 示例代码
<!--
* @Descripttion: 使用jsplumb插件实现连线功能
* @version:
* @Author: zhangfan
* @email: 2207044692@qq.com
* @Date: 2021-10-15 17:27:24
* @LastEditors: zhangfan
* @LastEditTime: 2022-06-02 10:38:39
-->
<template>
<div class="content" id="plumbContent">
<div class="left">
<div class="top">项目</div>
<ul class="bottom" id="leftBottom">
<li
v-for="(item, index) in leftData"
:key="index"
:id="item.id"
name="source"
>
{{ item.label }}
</li>
</ul>
</div>
<div class="right">
<div class="top">负责人</div>
<ul class="bottom" id="rightBottom">
<li
v-for="item in rightData"
:key="item.id"
:id="item.name"
name="target"
class="itemLi"
>
<div>{{ item.name }}</div>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
leftData: [
{
id: 1,
label: "项目1",
},
{
id: 2,
label: "项目2",
},
{
id: 3,
label: "项目3",
},
{
id: 4,
label: "项目4",
},
{
id: 5,
label: "项目5",
},
{
id: 6,
label: "项目6",
},
],
rightData: [
{
id: 1,
name: "张三",
},
{
id: 2,
name: "李四",
},
{
id: 3,
name: "王五",
},
],
plumbins: null, // 缓存实例化的jsplumb对象
connection: [],
connectionList: [], //手动维护一个关系
};
},
methods: {
init() {
// 初始化实例
this.$jsPlumb.ready(() => {
this.plumbins = this.$jsPlumb.getInstance({
Container: "plumbContent", // 选择器id
Connector: ["Straight"], //直线连接
});
// 双击删除连线
this.plumbins.bind("dblclick", (connection, originalEvent) => {
this.plumbins.deleteConnection(connection);
});
this.plumbins.bind("connection", (conn, originEvent) => {
// 数据存入
let obj = {};
obj.sourceId = conn.sourceId;
obj.targetId = conn.targetId;
console.log(obj);
console.log(this.plumbins.getConnections()); //获取连线数据
});
this.plumbins.batch(() => {
this.leftData.forEach((item, index) => {
this.initNode(item.id, "source");
});
this.rightData.forEach((item, index) => {
this.initNode(item.name, "target");
});
});
// 添加列表支持滚动
this.plumbins.addList(leftBottom);
this.plumbins.addList(rightBottom);
});
},
initNode(id, type) {
// 初始化点使其可以连接
const ins = this.plumbins;
const elements = document.getElementById(id);
if (type === "source") {
ins.makeSource(elements, {
// 锚点
anchor: [1, 0.5, 0, 0],
allowLoopback: false,
maxConnections: 1, //一对一就把maxConnections设置为1,一对多就设置为-1
// 锚点样式
paintStyle: {
fill: "skyblue",
strokeWidth: 3,
radius: 5,
},
hoverPaintStyle: { fill: "red" },
// 连线样式
connectorStyle: {
outlineStroke: "skyblue",
strokeWidth: 3,
},
connectorHoverStyle: {
strokeWidth: 6,
stroke: "red",
outlineStroke: "red",
},
});
} else {
ins.makeTarget(elements, {
anchor: [0, 0.5, 1, 0], // 锚点
// 锚点样式
paintStyle: {
strokeWidth: 2,
radius: 20,
},
allowLoopback: false,
maxConnections: -1, //一对一就把maxConnections设置为1,一对多就设置为-1
paintStyle: {
fill: "skyblue",
strokeWidth: 3,
radius: 5,
},
endpointHoverStyle: { fill: "red" },
});
}
},
setjsPlumb(sourceFlag, targetFlag) {
const source = document.getElementsByName("source");
const target = document.getElementsByName("target");
this.plumbins.setSourceEnabled(source, sourceFlag);
this.plumbins.setTargetEnabled(target, targetFlag);
this.plumbins.setDraggable(source, true); // 是否支持拖拽
this.plumbins.setDraggable(target, true); // 是否支持拖拽
},
repaintPlumb() {
this.plumbins.repaintEverything();
},
repaintConnetion(connetionList) {
if (this.$store.state.lines.connetions.length != 0) {
let connect = this.$store.state.lines.connetions.concat([]);
this.$nextTick(() => {
// 根据commonJS中的列表重新划线
connect.forEach((item) => {
this.plumbins.connect({
source: item.sourceId,
target: item.targetId,
});
});
});
}
},
// 保存连线关系
getConnetion() {
this.connection = this.plumbins.getConnections();
},
},
mounted() {
this.init();
this.repaintConnetion();
// 每次页面大小改变重新绘画连线
window.addEventListener("resize", this.repaintPlumb);
},
};
</script>
<style lang="less" scoped>
::-webkit-scrollbar {
width: 0.2vw;
background-color: rgba(192, 192, 192, 0);
}
.diy_overlay {
width: 3vw;
background-color: red;
height: 3vw;
}
// #plumbContent {
// position: relative;
// }
.content {
display: flex;
justify-content: space-around;
user-select: none;
padding: 3vw;
position: relative;
overflow: scroll;
// height: 28vw;
}
.right,
.left {
// padding-right: 1vw;
color: #fff;
width: 30%;
position: relative;
text-align: center;
.top {
border: none;
font-size: 0.8vw;
font-weight: 600;
color: #fff;
}
.bottom {
position: relative;
height: 25vw;
overflow-y: scroll;
padding-right: 2vw;
border: 1px #fff solid;
margin: 0 auto;
width: 80%;
margin-top: 0.5vw;
li {
list-style: none;
display: inline-block;
margin-top: 1vw;
width: 100%;
cursor: pointer;
min-width: 5vw;
text-align: center;
border: 1px #fff solid;
}
}
}
.right {
width: 60%;
.bottom {
li {
color: #fff;
border: 1px #fff solid;
padding: 1vw 0;
div {
border: 1px #fff solid;
border-radius: 3px;
display: inline-block;
margin-left: 0.5vw;
padding: 0 0.2vw;
}
}
}
}
.endpointLabel {
color: red;
font-size: 0.5vw;
font-weight: 600;
cursor: pointer;
}
</style>