Canvas图片画不出来主因是时机和参数问题:必须等img.onload触发后绘制,且drawImage参数需按需求选型;跨域图要设crossOrigin,本地文件用createObjectURL也需监听onload。

Canvas里图片画不出来,通常不是代码写错了,而是时机没卡准、参数没理清。核心就两点:图像必须加载完成才能画;drawImage 的参数顺序和含义得对上实际需求。
必须等 onload 触发后再绘制
图片通过 img.src = 'xxx.png' 加载是异步的,赋值完立刻调用 drawImage,图还没解码好,画布就是空的——控制台不报错,但什么也看不到。
-
正确做法:把
drawImage放进img.onload回调里,且src赋值要写在onload绑定之后 - 跨域图片(比如 CDN 上的图标)要加
img.crossOrigin = 'anonymous',否则后续读像素或导出数据会失败 - 用
URL.createObjectURL(file)加载本地文件,同样要监听onload,不能假设 URL 创建完就能立刻画
三种 drawImage 参数形式怎么选
别死记几个参数,关键看你要不要“裁剪”。所有重载的第一个参数都必须是已加载的合法图像源(HTMLImageElement 等),顺序错或类型不对,结果就不可预期。
-
drawImage(img, dx, dy):整张图原尺寸,左上角落在(dx, dy)。适合贴水印、放图标 -
drawImage(img, dx, dy, dWidth, dHeight):整张图缩放到指定宽高,仍以(dx, dy)为左上角。注意非等比缩放会拉伸变形 -
drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight):先从原图截一块区域,再把它画到目标位置并缩放。做帧动画、UI 切图复用时常用
容易忽略的边界与异常情况
这些情况不会报错,但图就是不出现或只显示一部分,调试时特别难察觉。
- 裁剪区域超出原图范围(比如
sx + sWidth > img.width),只会取有效部分,其余丢弃 - 目标宽高设为 0 或负数,整个绘制会被跳过,画布没变化
- 传入的不是
HTMLImageElement(比如传了字符串路径、未加载的img对象),控制台会报类型错误 - 用另一个
<canvas></canvas>当图像源,得确认它已经执行过绘图操作(比如fillRect),否则内容为空
实用建议:封装一个可靠加载函数
把加载逻辑抽出来,避免每次重复写 onload 和错误处理。
- 返回 Promise,方便配合
async/await - 自动处理
crossOrigin和onerror - 支持传入原始宽高,也支持留空让函数用
naturalWidth/Height - 绘制前可选清空画布,避免旧内容干扰


















