js写法 参考 https://juejin.cn/post/6915642997195407368
效果图
js实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>连线demo</title>
<script type="text/javascript" src="./jsplumb.js"></script>
<style>
.ul-list {
display: inline-block;
}
.ul-list li {
list-style-type: none;
border: 1px solid red;
height: 30px;
line-height: 30px;
text-align: center;
width: 100px;
}
</style>
</head>
<body>
<div>
<div><button id="btn">获取连线</button></div>
<textarea rows="5" cols="50" class="textarea"> </textarea>
<div id="container"></div>
</div>
<script>
// 定义列表数据
let data;
// 定义默认连线关系数据
let relationship;
// 定义jsplumb实例变量
let instance;
data = [
[
{
title: "我是a1啦啦",
id: "a1",
},
{
title: "我是a2啦啦",
id: "a2",
},
{
title: "我是a3啦啦",
id: "a3",
},
],
[
{
title: "我是b1啦啦",
id: "b1",
},
{
title: "我是b2啦啦",
id: "b2",
},
{
title: "我是b3啦啦",
id: "b3",
},
],
[
{
title: "我是c1啦啦",
id: "c1",
},
{
title: "我是c2啦啦",
id: "c2",
},
{
title: "我是c3啦啦",
id: "c3",
},
],
];
relationship = [
{ source: "a1", target: "b1" },
{ source: "a1", target: "b2" },
{ source: "b1", target: "c3" },
];
// 循环列表数据 渲染列表ul
data.forEach((v1, i1) => {
let ul = document.createElement("ul");
// 添加一个类名 方便后期获取
ul.classList.add("ul-list");
let lis = "";
v1.forEach((v2) => {
// id必须设置为数据的id 再添加自定义属性index值为当前列表索引 后期需要用到
lis += `<li id=${v2.id} index=${i1}>${v2.title}</li>`;
});
ul.innerHTML = lis;
document.getElementById("container").appendChild(ul);
});
jsPlumb.ready(function () {
// 初始化jsPlumb 创建jsPlumb实例
init();
// 设置可以为连线起点和连线终点的元素
setContainer();
// 设置默认连线
setConnect();
// 在连线事件中 只允许连接相邻的列表 不能跨列表连接
setRule();
jsPlumb.fire("jsPlumbDemoLoaded", instance);
});
// 初始化jsPlumb 创建jsPlumb实例
function init() {
instance = jsPlumb.getInstance({
Connector: "Straight", //连接线形状 Bezier: 贝塞尔曲线Flowchart: 具有90度转折点的流程线 StateMachine: 状态机 Straight: 直线
// PaintStyle: { strokeWidth: 3, stroke: "#ffa500", "dashstyle": "2 4" }, //连接线样式
Endpoint: ["Dot", { radius: 5 }], //端点
EndpointStyle: { fill: "#ffa500" }, //端点样式
Container: "container", //目标容器id
ListStyle: {
endpoint: ["Rectangle", { width: 30, height: 30 }],
},
});
}
// 设置可以连线的元素
function setContainer() {
//相当于css选择器 也可以使用id选择等
let uls = jsPlumb.getSelector(".ul-list");
// 将dom元素设置为连线的起点或者终点 设置了起点的元素才能开始连线 设置为终点的元素才能为连线终点
instance.batch(function () {
uls.forEach((ul) => {
let lis = ul.querySelectorAll("li");
lis.forEach((li) => {
// 将li设置为起点
instance.makeSource(li, {
allowLoopback: false,
anchor: ["Left", "Right"], // 设置端点位置
});
// 将li设置为终点
instance.makeTarget(li, {
anchor: ["Left", "Right"],
});
});
});
});
}
// 设置默认连线
function setConnect() {
relationship.forEach(function (el) {
// source是连线起点元素id target是连线终点元素id
instance.connect({ source: el.source, target: el.target });
});
}
// 只允许连接相邻的列表
function setRule() {
// // 连线事件 不不允许连接当前所在list
instance.bind("connection", function (connInfo, originalEvent) {
// connInfo是jsPlumb对象 可以打印出来康康有哪些东西
// 根据sourceId拿到开始连接元素li 再根据li的index自定义属性 判断只允许连接相邻的ul列表
let index = Number(
document
.getElementById(connInfo.connection.sourceId)
.getAttribute("index")
);
let allow = [];
if (data[index + 1]) {
allow = [...allow, ...data[index + 1].map((_) => _.id)];
}
if (data[index - 1]) {
allow = [...allow, ...data[index - 1].map((_) => _.id)];
}
// 如果连线终点元素(targetId)不在起点元素(sourceId)的前后ul列表范围 就删除该连线
if (allow.indexOf(connInfo.connection.targetId) == -1) {
// 删除连线
instance.deleteConnection(connInfo.connection);
}
});
}
// 给button注册点击事件获取连线关系
document.getElementById("btn").addEventListener("click", function () {
let newRelationship = '';
instance.getAllConnections().forEach((el) => {
newRelationship+=` ${el.sourceId}连接了${el.targetId}`;
});
document.querySelector('.textarea').value = newRelationship
console.log(document.querySelector('.textarea'));
// jsplumb常用方法
// jsplumb.getConnections({souce: 'sourceID', target: 'targetID'}); //获取指定连线
// 1. jsPlumb.getAllConnections() 获取所有连接线
// 2. jsPlumb.deleteEveryConnection(); 清空所有连接线
// 3. jsPlumb.deleteConnection(connInfo.connection); //删除连接线
// 4. jsPlumb.setContainer(document.getElementById("main"));//初始化实例化组件
});
</script>
</body>
</html>
vue改动(此处把线改成单条)
<template>
<div>
<div><button id="btn" @click="getLianXian()">获取连线</button></div>
<textarea rows="5" cols="50" class="textarea" v-model="textareaVal">
</textarea>
<div id="container">
<ul class="ul-list" v-for="(item, index) in data" :key="index">
<li
v-for="(i, indexes) in item"
:id="i.id"
:index="index"
:key="indexes"
>
{{ i.title }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data() {
return {
data: [
[
{
title: "我是a1",
id: "a1",
},
{
title: "我是a2",
id: "a2",
},
{
title: "我是a3",
id: "a3",
},
],
[
{
title: "我是b1",
id: "b1",
},
{
title: "我是b2",
id: "b2",
},
{
title: "我是b3",
id: "b3",
},
],
],
relationship: [
{ source: "a1", target: "b2" },
{ source: "a2", target: "b1" },
],
instance: "",
addponit: "",
textareaVal: "",
};
},
computed: {},
mounted() {
this.$nextTick(() => {
jsPlumb.ready(() => {
// 初始化jsPlumb 创建jsPlumb实例
this.init();
// 设置可以为连线起点和连线终点的元素
this.setContainer();
// 设置默认连线
this.setConnect();
// 在连线事件中 只允许连接相邻的列表 不能跨列表连接
this.setRule();
// 点击删除连线
this.delete();
// 判断是否建立连接
this.beforeDrop();
jsPlumb.fire("jsPlumbDemoLoaded", this.instance);
});
// jsplumb常用方法
// jsplumb.getConnections({souce: 'sourceID', target: 'targetID'}); //获取指定连线
// 1. jsPlumb.getAllConnections() 获取所有连接线
// 2. jsPlumb.deleteEveryConnection(); 清空所有连接线
// 3. jsPlumb.deleteConnection(connInfo.connection); //删除连接线
// 4. jsPlumb.setContainer(document.getElementById("main"));//初始化实例化组件
});
},
methods: {
// 初始化jsPlumb 创建jsPlumb实例
init() {
this.instance = jsPlumb.getInstance({
Connector: "Straight", //连接线形状 Bezier: 贝塞尔曲线Flowchart: 具有90度转折点的流程线 StateMachine: 状态机 Straight: 直线
// PaintStyle: { strokeWidth: 3, stroke: "#ffa500", "dashstyle": "2 4" }, //连接线样式
Endpoint: ["Dot", { radius: 5 }], //端点
EndpointStyle: { fill: "#000" }, //端点样式
Container: "container", //目标容器id
ListStyle: {
endpoint: ["Rectangle", { width: 30, height: 30 }],
},
});
},
// 设置可以连线的元素
setContainer() {
//相当于css选择器 也可以使用id选择等
let uls = jsPlumb.getSelector(".ul-list");
// 将dom元素设置为连线的起点或者终点 设置了起点的元素才能开始连线 设置为终点的元素才能为连线终点
this.instance.batch(() => {
uls.forEach((ul) => {
let lis = ul.querySelectorAll("li");
lis.forEach((li) => {
// 将li设置为起点
this.instance.makeSource(li, {
allowLoopback: false,
anchor: ["Left", "Right"], // 设置端点位置
});
// 将li设置为终点
this.instance.makeTarget(li, {
anchor: ["Left", "Right"],
});
});
});
});
},
// 设置默认连线
setConnect() {
this.relationship.forEach((el) => {
// source是连线起点元素id target是连线终点元素id
this.instance.connect({ source: el.source, target: el.target });
});
},
// 只允许连接相邻的列表
setRule() {
// // 连线事件 不不允许连接当前所在list
this.instance.bind("connection", (connInfo, originalEvent) => {
// connInfo是jsPlumb对象 可以打印出来康康有哪些东西
// 根据sourceId拿到开始连接元素li 再根据li的index自定义属性 判断只允许连接相邻的ul列表
let index = Number(
document
.getElementById(connInfo.connection.sourceId)
.getAttribute("index")
);
let allow = [];
if (this.data[index + 1]) {
allow = [...allow, ...this.data[index + 1].map((_) => _.id)];
}
if (this.data[index - 1]) {
allow = [...allow, ...this.data[index - 1].map((_) => _.id)];
}
// 如果连线终点元素(targetId)不在起点元素(sourceId)的前后ul列表范围 就删除该连线
if (allow.indexOf(connInfo.connection.targetId) == -1) {
// 删除连线
this.instance.deleteConnection(connInfo.connection);
}
});
},
delete() {
this.instance.bind("click", (conn, originalEvent) => {
if (window.prompt("确定删除所点击的链接吗? 输入1确定") === "1") {
this.instance.deleteConnection(conn);
}
});
},
beforeDrop() {
// 当链接建立前
this.instance.bind("beforeDrop", (info) => {
let checkArrsourceId = [];
let checkArrtargetId = [];
this.instance.getAllConnections().forEach((el) => {
checkArrsourceId.push(el.sourceId);
checkArrtargetId.push(el.targetId);
});
let fenId = checkArrsourceId.concat(checkArrtargetId);
console.log(fenId, "fenId-----");
console.log(fenId.indexOf(info.sourceId), "allId.indexOf(fenId)====");
if (
fenId.indexOf(info.sourceId) == -1 ||
fenId.indexOf(info.targetId) == -1
) {
return true; // 链接会自动建立
} else {
return false; // 链接不会建立,注意,必须是false
}
});
},
getLianXian() {
let newRelationship = "";
this.instance.getAllConnections().forEach((el) => {
newRelationship += ` ${el.sourceId}连接了${el.targetId}`;
});
this.textareaVal = newRelationship;
},
},
};
</script>
<style>
* {
padding: 1;
margin: 1;
}
#container {
width: 500px;
}
.ul-list {
display: inline-block;
}
.ul-list li {
list-style-type: none;
border: 1px solid red;
height: 30px;
line-height: 30px;
text-align: center;
width: 100px;
}
</style>