RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1013276
Accepted
Talleyran
Talleyran
Asked:2020-08-14 03:57:17 +0000 UTC2020-08-14 03:57:17 +0000 UTC 2020-08-14 03:57:17 +0000 UTC

如何在 Vue 中的 DOM 更改上正确重建 jsPlumb

  • 772

在 Vue 的帮助下,块从对象中循环显示。对不起,这个例子很长,但我不知道如何简化以重现问题。

var blocks1 = [{
    id: "b1",
    pos: [20, 100],
    routes: [{
      id: "r1",
      target: "b2"
    }, {
      id: "r2",
      target: "b3"
    }]
  },
  {
    id: "b2",
    pos: [130, 50]
  },
  {
    id: "b3",
    pos: [130, 150]
  }
];

var blocks2 = [{
    id: "b4",
    pos: [25, 110]
  },
  {
    id: "b5",
    pos: [120, 60],
    routes: [{
      id: "r3",
      target: "b4"
    }, {
      id: "r4",
      target: "b6"
    }]
  },

  {
    id: "b6",
    pos: [135, 140]
  }
];

var jsp = jsPlumb.getInstance({
  Container: "jsp",
  Anchors: ["Right", "Left"]
});

var app = new Vue({
  el: "#app",
  data: {
    blocks: blocks1
  },
  mounted: function() {
    console.clear();
    console.log("vue mounted");
    drawLines();
    makeDraggable();
  },
  updated: function() {
    console.log("vue changed");
    drawLines(); //рисуем связи заново
    //makeDraggable(); почему работает без этого?
  },
  methods: {
    changeData: function() {
      jsp.reset(); //сбрасываем jsplumb
      this.blocks = blocks2; //меняем данные
    }
  }
});

function makeDraggable() {
  let blocks = document.querySelectorAll(".block");
  for (var block of blocks) {
    jsp.draggable(block.id);
  }
}

function drawLines() { //перебираем маршруты
  let routes = document.querySelectorAll(".route");
  for (var route of routes) {
    drawLine(route);
  }
}

function drawLine(route) { //рисуем связь
  jsp.connect({
    source: route.id,
    target: route.dataset.target
  });
}
.block {
  position: absolute;
  padding: 1rem;
  background-color: #eee;
}

.jtk-endpoint {
  display: none;
}
<div id="jsp">
  <div id="app">
    <button @click="changeData">change data</button>
    <div class="block" v-for="block in blocks" :id="block.id" :style="{top:block.pos[1]+'px', left:block.pos[0]+'px'}">
      <div class="title">{{block.id}}</div>
      <div class="routes">
        <div class="route" v-for="route in block.routes" :data-target="route.target" :id="route.id">
          {{route.target}}
        </div>
      </div>
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jsPlumb/2.11.2/js/jsplumb.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>

有 jsPlumb,它在将 DOM 渲染到 hook 之后mounted(),使这些块可拖动并在它们之间绘制链接。到目前为止一切顺利,一切正常。

现在我想加载另一个框图并更改对象。我用方法重置jsPlumb reset(),Vue重绘新块,jsPlumb重绘链接,但是当用传出链接拖动b5块时,一切都中断了。

在日志中给出:

jsPlumb 函数失败:TypeError:无法读取未定义的属性“el”

如何解决?

还有一个问题,为什么新绘制的方块会变成可拖动的?看来 Vue 并没有完全擦除它们,而是改变了相同数量的块的内容,留下了事件。

UPD:是的,vue 只是更改块的 id 和内容,而不是从 dom 中删除它们并重新创建它们。如何改变这种行为?

codepen上的完整示例

vue.js
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Talleyran
    2020-08-16T06:16:24Z2020-08-16T06:16:24Z

    我自己想通了。Vue 并没有真正完全重绘块。因此,来自 jsPlumb 的事件和类仍保留在它们上。要强制 Vue 完全重绘块,您需要通过显式添加属性来告诉它它们是不同的key。

    <div v-for="(block,index,key) in blocks" :key="block.id" ... >
    

    值必须是唯一的,比如 id,那么 Vue 就会明白这些是不同的块。

    var blocks1 = [{
        id: "b1",
        pos: [20, 100],
        routes: [{
          id: "r1",
          target: "b2"
        }, {
          id: "r2",
          target: "b3"
        }]
      },
      {
        id: "b2",
        pos: [130, 50]
      },
      {
        id: "b3",
        pos: [130, 150]
      }
    ];
    
    var blocks2 = [{
        id: "b4",
        pos: [25, 110]
      },
      {
        id: "b5",
        pos: [120, 60],
        routes: [{
          id: "r3",
          target: "b4"
        }, {
          id: "r4",
          target: "b6"
        }]
      },
    
      {
        id: "b6",
        pos: [135, 140]
      }
    ];
    
    var jsp = jsPlumb.getInstance({
      Container: "jsp",
      Anchors: ["Right", "Left"]
    });
    
    var app = new Vue({
      el: "#app",
      data: {
        blocks: blocks1
      },
      mounted: function() {
        console.clear();
        console.log("vue mounted");
        drawLines();
        makeDraggable();
      },
      updated: function() {
        console.log("vue changed");
        drawLines(); //рисуем связи заново
        makeDraggable(); //возвращаем перетаскивание
      },
      methods: {
        changeData: function() {
          jsp.reset(); //сбрасываем jsplumb
          this.blocks = this.blocks==blocks1 ? blocks2 : blocks1; //меняем данные
        }
      }
    });
    
    function makeDraggable() {
      let blocks = document.querySelectorAll(".block");
      for (var block of blocks) {
        jsp.draggable(block.id);
      }
    }
    
    function drawLines() { //перебираем маршруты
      let routes = document.querySelectorAll(".route");
      for (var route of routes) {
        drawLine(route);
      }
    }
    
    function drawLine(route) { //рисуем связь
      jsp.connect({
        source: route.id,
        target: route.dataset.target
      });
    }
    .block {
      position: absolute;
      padding: 1rem;
      background-color: #eee;
    }
    
    .jtk-endpoint {
      display: none;
    }
    <div id="jsp">
      <div id="app">
        <button @click="changeData">change data</button>
        <div class="block" v-for="(block,index,key) in blocks" :key="block.id" :id="block.id" :style="{top:block.pos[1]+'px', left:block.pos[0]+'px'}">
          <div class="title">{{block.id}}</div>
          <div class="routes">
            <div class="route" v-for="route in block.routes" :data-target="route.target" :id="route.id">
              {{route.target}}
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsPlumb/2.11.2/js/jsplumb.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>

    • 0

相关问题

  • 为什么单击与该方法无关的按钮时会调用该方法?

  • Vue js如何让表格滑动顺畅

  • Vue.js 复选框问题

  • 如何在 nuxt 中将 html 添加到翻译中?

  • 如何给v-dialog组件属性border-radius:10px?

  • 快递发送vue模板邮件

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5