我正在编写一个贺卡生成器以在 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.h
。 size
是 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 请求。
关于image - 背景图像没有以奇怪的方式显示在 Canvas 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65491291/