基于jsplumb.js实现多列表一对多连线效果

本文展示了如何在Vue中使用jsPlumb库创建一个连线功能的示例。首先,通过jsPlumb实例化创建连接线,并设置起点和终点。接着,通过遍历数据生成列表并设置连线规则,只允许连接相邻的列表。最后,添加按钮监听事件,获取并显示当前的连线关系。此外,还提供了删除连线和判断连接是否合法的函数。
摘要由CSDN通过智能技术生成

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值