如何使用 Vue 在 div 中加载 canvas?

How can I load a canvas inside a div with Vue?

我真的是 Vue 的新手,对于这个项目,我试图在 div 中加载 canvas。如果 canvas 在 div 之外加载,它可以正常工作,但我想在 loadModal 为真时显示 canvas。在此代码中,我使用了两个 canvas,一个在 div 内,另一个在 div 外。它仅在 div 之外正确加载 canvas。有没有办法在 div 中也加载 canvas ?下面是我在 JsFiddle

上的代码

JsFiddle 代码 = https://jsfiddle.net/ujjumaki/6vg7r9oy/9/

查看

<div id="app">
  <button @click="runModal()">
  Click Me
  </button>
  <br><br>
  <div v-if="loadModal == true">
    <canvas id="myCanvas" width="200" height="100" style="border:3px solid #d3d3d3; color:red;">
    </canvas>
  </div>
  
  <!-- this one loads correctly -->
  <canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
  </canvas>
</div>

方法

new Vue({
  el: "#app",
  data: {
    loadModal: false,
  },
  methods: {
    runModal(){
        this.loadModal = true;
      var c = document.getElementById("myCanvas");
      var ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.arc(95, 50, 40, 0, 2 * Math.PI);
      ctx.stroke();
    }
  }
})

尝试使用 v-show 和 class 代替,这样您就可以 select 所有 div:

new Vue({
  el: "#app",
  data: {
    loadModal: false,
  },
  methods: {
    runModal(){
        this.loadModal = true;
      const c = document.querySelectorAll("canvas");
      c.forEach(can => {
        let ctx = can.getContext("2d");
        ctx.beginPath();
        ctx.arc(95, 50, 40, 0, 2 * Math.PI);
        ctx.stroke();
      })
    }
  }
})

Vue.config.productionTip = false
Vue.config.devtools = false
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}
#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}
li {
  margin: 8px 0;
}
h2 {
  font-weight: bold;
  margin-bottom: 15px;
}
del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button @click="runModal()">
  Click Me
  </button>
  <br><br>
  <div v-show="loadModal == true">
    <canvas class="canvas" id="myCanvas" width="200" height="100" style="border:3px solid #d3d3d3; color:red;">
    </canvas>
  </div>
  <canvas class="canvas" id="myCanvas" width="200" height="100" style="border:3px solid #d3d3d3; color:red;">
  </canvas>
</div>

问题是 runModal()loadModal 设置为 true 并且 立即 尝试引用有条件渲染的 <canvas> <div v-if="loadModal">,但 <div>(及其 <canvas>)仍未呈现 loadModal 更改的效果要到下一个渲染周期才会完成。 <div> 之外的 <canvas> 正确“加载”,因为它不是有条件地呈现。

一个解决方案是 await the next render cycle with the $nextTick() callback 尝试访问 <canvas>:

new Vue({
  methods: {
    async runModal() {
      this.loadModal = true;

      // await next render cycle
      await this.$nextTick();

      // <canvas id="myCanvas"> is available here
      var c = document.getElementById("myCanvas");
      ⋮
    }
  }
})

updated fiddle

或者,使用 <div v-show="loadModal">(如另一个答案中所述)也有效,因为 <canvas> 已经呈现在文档中,因此可供查询。如果您更喜欢 lazily render<canvas>,请坚持使用 v-if="loadModal"