Canvas绘图依赖状态驱动的2D上下文,需手动管理图像加载、样式设置和路径重置:drawImage前须等img.onload;fillRect/strokeRect依赖当前fillStyle/strokeStyle;多路径绘制必须用beginPath()隔离。
Canvas 绘图不是“写个函数就能出图”,关键在于理解 getContext('2d') 返回的绘图上下文对象如何被状态驱动——它没有自动重绘、不保留图形历史、所有操作都依赖当前路径和样式状态。

常见原因是图像未加载完成就调用绘图方法。Canvas 不会等待图片加载,drawImage 对未就绪的 HTMLImageElement 无效,也不会报错。
img.onload,再调用 ctx.drawImage(img, x, y)
URL.createObjectURL(file) 加载本地文件时,也要等 load 事件new Image() 同样需要 onload
这两个方法本身不设置颜色,完全依赖上下文当前的 fillStyle 或 strokeStyle 值。如果没显式设置,它们会沿用默认值(fillStyle = '#000000',但若之前被设为透明色或非法值,就会“看不见”)。
ctx.fillStyle = 'red' 必须在 fillRect 前执行;同理 strokeStyle 对 strokeRect
'transparent' 或 'rgba(0,0,0,0)' 会导致“画了等于没画”当你要绘制**多个独立路径**(比如两个不相连的圆),且不希望它们被意外连接时,beginPath() 是必须的。Canvas 路径是累积的,stroke() 或 fill() 会作用于整个当前路径。
beginPath():第二个 arc() 会被追加到第一个路径里,stroke() 可能画出一条连接线ctx.beginPath();ctx.clearRect() 只擦画布像素,不重置路径beginPath() 的习惯——避免因复用上下文导致路径污染Canvas 的“难”不在 API 多,而在它把渲染控制权全交给你:没有图层、没有自动更新、没有坐标系封装。一个漏掉的 beginPath()、一次提前的 stroke()、一张没等加载的图片,都足以让画面静默——这些地方没法靠 console 看出来,得靠对状态流的预判。