必须调用 getContext('2d') 获取绘图上下文,否则无法绘制;drawImage 需在 img.onload 中调用以防图片未加载;clearRect 仅清指定区域,不重置样式;toDataURL 失败多因跨域污染,需设 crossOrigin="anonymous"。

怎么获取 canvas 的 2D 绘图上下文
不调用 getContext('2d'),canvas 元素就只是个空壳,所有绘制操作都无从谈起。常见错误是直接对 canvas 元素调用 fillRect 这类方法,结果报错:TypeError: canvas.fillRect is not a function。
必须先拿到上下文对象,它才是真正的绘图接口:
- 确保 DOM 已加载完成,否则
document.getElementById返回null -
getContext('2d')是最常用、兼容性最好的方式;getContext('webgl')属于另一套体系,别混用 - 返回值可能为
null(比如浏览器不支持或参数错误),建议加一层判断
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error('2D context not supported');
}
为什么 drawImage 画不出图片或只显示一半
这是 canvas 最高频的“黑屏”问题——图片没加载完就调用了 drawImage。canvas 不会等图片加载,它只认当前 img 元素的 width/height 和像素数据,而刚设置 src 时这些都还没就绪。
正确做法只有这一种:把 drawImage 放进 img.onload 回调里:
立即学习“前端免费学习笔记(深入)”;
- 不要用
setTimeout模拟等待,不可靠 - 如果图片来自本地文件或 Blob,也要走
URL.createObjectURL+onload流程 -
drawImage有 3 种参数签名,最常用的是drawImage(img, x, y)和drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh),缩放裁剪时容易传错顺序
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0); // 此时 img.width/height 已可用
};
img.src = '/path/to/image.png';
clearRect 清不干净?或者清掉了不该清的内容
clearRect 只擦除指定矩形区域的像素,不是“重置整个画布状态”。它不会影响已设置的 fillStyle、lineWidth 等上下文属性,也不会清除用 putImageData 写入的像素(除非刚好覆盖)。
常见误用场景:
- 想清空整块画布却只写了
clearRect(0, 0, 100, 100),而 canvas 实际宽高是 800×600 - 在动画循环中反复
clearRect+draw,但忘了每次都要重设颜色、字体等状态,导致样式残留 - 用
clearRect擦除某图形后,又用stroke或fill绘制新内容,结果发现线条变细了——其实是之前设置的lineWidth被覆盖了
安全做法是显式重置关键状态,或用 save()/restore() 隔离:
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#000'; // 显式重置,别依赖上一次值
toDataURL 导出空白或黑图怎么办
toDataURL 返回空字符串或黑图,90% 是因为跨域问题。只要图片来自其他域名(包括 file:// 协议打开的本地 HTML),且服务器没配 CORS 头,canvas 就会被标记为“污染”,禁止读取像素数据。
现象很隐蔽:绘图一切正常,drawImage 成功,但一调 toDataURL 就返回 "data:," 或报错 SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement'。
- 本地开发时,别用
file://直接双击打开 HTML,启动一个本地服务(如npx serve) - 线上图片需确保服务端返回
Access-Control-Allow-Origin: *,且 JS 加载时带上crossOrigin="anonymous" - 如果无法控制图片源,可尝试用代理接口中转,或改用
createImageBitmap(部分场景下绕过限制)
const img = new Image(); img.crossOrigin = 'anonymous'; // 关键! img.src = 'https://example.com/image.png';事情说清了就结束











