drawImage()图片不显示主因是参数顺序错误或图像未加载完成:①参数必须以图像对象开头,如ctx.drawImage(img,x,y);②必须监听img.onload事件并在回调中绘制,否则因异步加载导致naturalWidth为0而静默失败。

drawImage() 参数顺序写错,图片直接不显示
最常见的“画不出来”不是代码漏了,是 drawImage() 参数放反了。比如写成 ctx.drawImage(0, 0, img) —— 这会报错或静默失败,因为第一个参数必须是图像对象。正确顺序永远是图像在前,坐标/尺寸在后。
三套签名要分清:
-
drawImage(img, x, y):原图大小,左上角落在(x, y) -
drawImage(img, x, y, width, height):缩放绘制,width/height是目标区域尺寸 -
drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh):先从源图裁剪(sx,sy,sw,sh),再贴到目标位置并缩放到(dw,dh)
用错一套,轻则偏移、失真,重则整张图消失。尤其第三套,9个参数极易数错位置,建议拆成变量命名再传入。
图片还没加载完就 drawImage(),画布一片空白
这是最隐蔽也最高频的问题:img.src = 'xxx.png' 是异步的,赋值完立刻调 drawImage(),此时 img.naturalWidth 很可能是 0,canvas 什么也不会画,控制台还不报错。
必须等 onload 触发后再绘制:
-
onload 必须在设置
src之前绑定,否则可能错过事件(尤其是缓存命中时) - 不要用
img.complete判断——它只反映是否已缓存,不保证解码完成 - 如果图片来自用户上传(
File或URL.createObjectURL()),同样适用该规则
正确写法示例:
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0);
};
img.src = 'avatar.jpg'; // src 放最后
跨域图片被污染,drawImage() 后 canvas 不可读取
当 img.src 指向其他域名的图片(比如 CDN 链接),且你后续要用 ctx.getImageData() 或导出为 toDataURL(),就会触发“canvas 被污染”错误:SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
解决办法分两端:
- 前端:给
Image对象加crossOrigin属性,如img.crossOrigin = 'anonymous' - 服务端:图片资源响应头必须包含
Access-Control-Allow-Origin: *(或指定域名) - 注意:
crossOrigin必须在src赋值前设置,否则无效
drawImage() 画出来但位置/尺寸不对,检查坐标系和 canvas 像素比
Canvas 的绘图坐标基于 CSS 像素,但实际渲染分辨率由 canvas.width/canvas.height 决定。如果只用 CSS 缩放 canvas 元素(比如 style="width:300px;height:200px"),而没同步改 width/height 属性,图片就会被拉伸或压缩。
典型表现:
- 图片模糊、锯齿明显
- 用
drawImage(img, 0, 0, 100, 100)却铺满整个画布 - 鼠标点击坐标与绘制位置对不上
修复方式:
- 显式设置
canvas.width和canvas.height为真实像素尺寸 - 避免仅靠 CSS 缩放 canvas;如需响应式,用 JS 动态重设属性并重绘
- 高 DPI 设备(Retina)下,记得用
window.devicePixelRatio校正
真正麻烦的从来不是语法,而是 onload 绑太晚、crossOrigin 忘加、canvas 像素比没对齐——这三处一错,画得再准也没用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











