React 18中HTML Canvas图片渲染不稳定问题求助
问题原因与修复方案
核心问题
第二张图片(logo)无法渲染或消失的根本原因是图片加载的异步性:设置logoImage.src后立刻调用context.drawImage,此时图片大概率还没加载完成,Canvas无法绘制未加载完成的图片。此外还有几个次要问题会加剧这个现象:
- 错误处理函数绑定在
src设置之后,无法捕获加载初期的错误 - Canvas尺寸依赖未加载完成的
image.width,导致尺寸异常间接影响绘制
修复步骤
- 等待图片加载完成后再绘制:用
onload事件或Promise封装图片加载逻辑,确保两张图片都加载完成后再执行Canvas绘制 - 提前绑定错误/加载事件:在设置
src之前绑定onload和onerror,保证能正确捕获加载状态 - 避免依赖未加载图片的尺寸:要么用固定尺寸初始化Canvas,要么在图片加载完成后再动态调整
修改后的代码示例
// 封装图片加载的Promise工具函数 const loadImage = (src) => { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = (err) => reject(err); img.src = src; }); }; const handleDraw = async ( msg, fontSize, selectedFont, textColor, boldStyle, italicStyle, underlineStyle ) => { const canvas = canvasRef.current; if (!canvas) return; const context = canvas.getContext("2d"); const imgElement = document.getElementById("cardImage"); if (!imgElement) return; try { // 等待两张图片加载完成 const [image, logoImage] = await Promise.all([ loadImage(imageContent), loadImage(logo) ]); // 加载完成后再设置Canvas尺寸 canvas.width = image.width + 1200; canvas.height = image.height + 500; // 绘制主图 context.drawImage(image, 0, 0, imgElement.width + 150, imgElement.height - 20); // 绘制Logo(此时图片已加载完成) context.drawImage(logoImage, imgElement.width + 200, 0, 250, 100); // 设置文本样式并绘制 context.font = `${boldStyle ? "bold" : "normal"} ${italicStyle ? "italic" : "normal"} ${fontSize}px ${selectedFont}`; context.fillStyle = textColor; drawText(context, 400, 40, msg, imgElement.width + 160, imgElement.height / 6); } catch (err) { console.error("图片加载或绘制出错:", err); } }; function drawText(context, maxWidth, lineHeight, text, x, y) { const lines = text.split("\n"); const newLines = []; for (const line of lines) { let words = line.split(" "); let currentLine = words[0]; for (let i = 1; i < words.length; i++) { const width = context.measureText(`${currentLine} ${words[i]}`).width; if (width > maxWidth) { newLines.push(currentLine); currentLine = words[i]; } else { currentLine += ` ${words[i]}`; } } newLines.push(currentLine); } for (const line of newLines) { context.fillText(line, x, y); y += lineHeight; } }
关键说明
- 用
Promise.all同时加载两张图片,确保两者都准备好再绘制 - 把Canvas尺寸调整逻辑放在图片加载完成后,避免依赖未初始化的图片尺寸
- 修复了
context.font的空格问题(原代码中多余的空格可能导致字体样式失效) - 增加了Canvas和DOM元素的存在性检查,避免空指针错误
内容的提问来源于stack exchange,提问作者Dev
相关产品推荐
相关产品推荐

