image - 背景图像没有以奇怪的方式显示在 Canvas 上

标签 image vue.js canvas vuejs3

我正在编写一个贺卡生成器以在 VueJS 3 中进行训练。除了一件事之外,一切都正常工作,请查看我的代码:

<template>
  <div>
    <h1>greeting card generator</h1>
    <div class="board">
        <canvas id='myCanvas' :width="size.w" :height="size.h" tabindex='0'
style="border:1px solid #000000;"
        ></canvas>
    </div>
    <textarea
      :style="'width:' + size.w + 'px; resize:none;'"
      v-model="texte"
      placeholder="Write your text here">
    </textarea>
  </div>
</template>

<script>

import {
  defineComponent, onMounted, ref, reactive, watch,
} from 'vue';

export default defineComponent({
  setup() {
    const myCanvas = ref(null);
    const texte = ref('');
    const rapport = ref(0);

    const size = reactive({
      w: window.innerWidth * 0.8,
      h: (window.innerWidth * 0.8) / 1.8083832335329342,
    });

    function drawText() {
      const fontSize = 0.05 * window.innerWidth - 10;
      myCanvas.value.font = `${fontSize}px Adrip`;
      myCanvas.value.textAlign = 'center';
      const x = size.w / 2;
      const lineHeight = fontSize;
      const lines = texte.value.split('\n');
      for (let i = 0; i < lines.length; i += 1) {
        myCanvas.value.fillText(
          lines[lines.length - i - 1],
          x,
          (size.h * 0.98) - (i * lineHeight),
        );
      }
    }

    function initCarte() {
      const background = new Image();
      background.src = '/img/fond.jpeg';
      background.onload = function () {
        rapport.value = background.naturalWidth / background.naturalHeight;
        size.h = size.w / rapport.value;
        try {
          myCanvas.value.drawImage(background, 0, 0, size.w, size.h);
        } catch (e) {
          console.log(`ERREUR DE CHARGEMENT D'IMAGE: ${e}`);
        }
        drawText();
      };
    }

    function handleResize() {
      size.w = window.innerWidth * 0.8;
      size.h = size.w / rapport.value;
      initCarte();
    }

    window.addEventListener('resize', handleResize);

    onMounted(() => {
      const c = document.getElementById('myCanvas');
      const ctx = c.getContext('2d');
      myCanvas.value = ctx;
      initCarte();
    });

    watch(texte, () => {
      initCarte();
    });

    return {
      myCanvas,
      size,
      texte,
    };
  },
});

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
@font-face {
  font-family: 'Adrip';
  src: local('Adrip'), url('/fonts/adrip1.ttf') format('truetype');
}

#myCanvas {
  border: 1px solid grey;
}
</style>

看这一行:

h: (window.innerWidth * 0.8) / 1.8083832335329342,

如果我不对此进行硬编码,而仅输入规范值 window.innerWidth * 0.8,则图像不会显示,尽管 size.h = size.w/rapport .value; 行正确执行。

我真的不明白这种行为,有人可以向我解释一下吗? 另外,如果有人知道如何一次性加载图像,这样我就不必在每次刷新时加载它,那就更好了:)

提前致谢!

最佳答案

您的问题是,由于模板魔法的工作原理,您在绘制图像后更改了 Canvas 的大小。如果你把debugger放在后台onload函数的drawText();后面,你会看到它实际上绘制了图像。但是,在同一函数中,您设置了 size.hsize 是 react 性的,因此被标记为“脏”。模板中也使用了 size,因此模板被标记为脏。执行 onload 函数后,Vue 将重新渲染您的模板...并删除您的图像。

我认为最好的选择是使用nextTick。您需要谨慎使用它,但我认为这是您别无选择只能等待 DOM 解决的情况之一。为此,请从 vue 导入 nextTick:

import { nextTick } from 'vue';

然后用它包围你的 drawImage try-catch block 。

background.onload = function () {
  rapport.value = background.naturalWidth / background.naturalHeight;
  size.h = size.w / rapport.value;
  nextTick(() => {
    try {
      myCanvas.value.drawImage(background, 0, 0, size.w, size.h);
    } catch (e) {
      console.log(`ERREUR DE CHARGEMENT D'IMAGE: ${e}`);
    }
    drawText();
  });
};

至于你的最后一个问题如何加载图像一次......简短的答案是......你不能。每当 Canvas 发生变化时,您都需要重新绘制它。至少该图像应该由浏览器缓存,因此它只是从缓存中提取图像,而不是执行另一个 http 请求。

Edit Background image not showing on canvas in a strange way

关于image - 背景图像没有以奇怪的方式显示在 Canvas 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65491291/

相关文章:

image - 使用 Webpack 在 React 中加载图像

android - 如何避免 Picasso 对调整大小的图像重复发出网络请求?

vue.js - 禁用 eslint Vue.js

javascript - 如何隐藏/禁用 videojs 中的按钮控件?

javascript - Canvas 中的链接 (HTML5)

android - 单路径 Android 的多种颜色

jquery - 我怎样才能改变图像在 Jquery 中的位置?

html - 高分辨率图像 IE 浏览器渲染

javascript - 为什么在浏览器中不显示任何内容? (vue.js 2)

javascript - 手机间隙 : Canvas is not refreshing properly