Image 背景图像未以奇怪的方式显示在画布上
我正在编写一个贺卡生成器,以便在VueJS3中进行培训。一切正常,除了一件事,请看我的代码:Image 背景图像未以奇怪的方式显示在画布上,image,vue.js,canvas,vuejs3,Image,Vue.js,Canvas,Vuejs3,我正在编写一个贺卡生成器,以便在VueJS3中进行培训。一切正常,除了一件事,请看我的代码: <template> <div> <h1>greeting card generator</h1> <div class="board"> <canvas id='myCanvas' :width="size.w" :height="size.h&quo
<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>
如果我不硬编码,只输入规范值window.innerWidth*0.8
,图像不会显示,尽管size.h=size.w/rapport.value代码>行正确执行
我真的不明白这种行为,有人能给我解释一下吗?
另外,如果有人知道如何一次性加载图像,这样我就不必在每次刷新时都加载图像,那就更好了:)
提前谢谢 您的问题是,由于模板魔术的工作方式,在绘制图像后更改画布的大小。如果将debugger
放在drawText()后面
在后台onload函数中,您将看到它实际上绘制了图像。但是,在同一个函数中,您可以设置size.h
<代码>大小
是反应性的,因此标记为“脏”<代码>大小也用于模板中,因此模板被标记为脏。执行onload函数后,Vue将重新加载模板。。。并删除你的图像
我认为您最好在这里使用nextTick
。您需要谨慎地使用它,但我认为这是一种您别无选择只能等待DOM解决的情况。要执行此操作,请从vue导入nextTick
:
import { nextTick } from 'vue';
然后围绕您的drawImage
尝试用它捕捉块
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();
});
};
至于你的最后一个问题,如何加载图像一次。。。简单的回答是。。。你不能。每当画布更改时,都需要重新绘制它。至少浏览器应该缓存图像,所以它只是从缓存中提取图像,而不是执行另一个http请求
您的问题是,由于模板魔术的工作方式,在绘制图像后更改画布的大小。如果将
debugger
放在drawText()后面
在后台onload函数中,您将看到它实际上绘制了图像。但是,在同一个函数中,您可以设置size.h
<代码>大小是反应性的,因此标记为“脏”<代码>大小也用于模板中,因此模板被标记为脏。执行onload函数后,Vue将重新加载模板。。。并删除你的图像
我认为您最好在这里使用nextTick
。您需要谨慎地使用它,但我认为这是一种您别无选择只能等待DOM解决的情况。要执行此操作,请从vue导入nextTick
:
import { nextTick } from 'vue';
然后围绕您的drawImage
尝试用它捕捉块
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();
});
};
至于你的最后一个问题,如何加载图像一次。。。简单的回答是。。。你不能。每当画布更改时,都需要重新绘制它。至少浏览器应该缓存图像,所以它只是从缓存中提取图像,而不是执行另一个http请求
谢谢您的完整回答。我学习了“nextTick”,这是我以前不知道的:)谢谢你给我完整的答案。我学会了“nextTick”,这是我以前不知道的:)