Canvas绘图需先调用getContext('2d')获取上下文,再用fillRect()、strokeRect()画矩形,arc()配合beginPath()画圆,lineTo()等绘制路径;所有操作基于像素,无DOM绑定,交互与动画需手动管理状态和重绘。

Canvas 画基础图形不靠“绑定”,而是靠调用上下文方法实时绘制——没有 DOM 节点、不响应事件(除非手动加),画完即静态像素。想让图形可交互或复用,得自己管理状态和重绘逻辑。
fillRect() 和 strokeRect() 是画矩形最直接的方式
这两个方法独立于路径系统,不依赖 beginPath(),也不影响当前路径栈:
-
fillRect(x, y, width, height)填充实心矩形,颜色由fillStyle控制 -
strokeRect(x, y, width, height)只描边,线宽和颜色由lineWidth和strokeStyle决定 - 坐标系原点在左上角,
y增大方向是向下,不是数学坐标系 - 多次调用互不影响,无需手动
beginPath()或closePath() - 不支持圆角;若需圆角矩形,得用
rect()+arcTo()或离屏 canvas 配合clip()
示例:
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#4a90e2';
ctx.fillRect(10, 20, 120, 80);
ctx.strokeStyle = '#d32f2f';
ctx.lineWidth = 3;
ctx.strokeRect(50, 60, 100, 40);
画圆必须用 arc(),且必须配合 beginPath()
Canvas 没有 drawCircle() 这类便捷方法,arc() 是唯一标准方式。漏掉 beginPath() 是新手最常踩的坑:
-
arc(x, y, radius, startAngle, endAngle, anticlockwise)中角度单位是弧度,不是度数 - 画整圆要确保
endAngle - startAngle === 2 * Math.PI,比如0到Math.PI * 2 - 不调
beginPath()就直接arc()+fill(),会导致新圆和之前所有未闭合路径一起被填充 -
arcTo()不适合画标准圆,它只适用于已有两条切线的路径连接场景
正确写法:
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(150, 100, 40, 0, Math.PI * 2);
ctx.fillStyle = '#7c4dff';
ctx.fill();
线段和不规则图形靠 moveTo() + lineTo() + stroke()
这是路径式绘图的核心流程,和矩形/圆不同,它依赖路径状态管理:
立即学习“前端免费学习笔记(深入)”;
- 先调
beginPath()清空当前路径,避免叠加 -
moveTo(x, y)设起点,lineTo(x, y)加线段,可链式多次调用 - 最后用
stroke()描边或fill()填充(需closePath()才能形成封闭区域) - 如果只画一条线,不
beginPath()问题不大;但画多条独立线时,不重置路径会连成折线 -
lineCap和lineJoin影响端点和拐角样式,lineWidth必须在stroke()前设置才生效
示例(画三角形):
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(100, 150);
ctx.closePath();
ctx.fillStyle = 'orange';
ctx.fill();
图形不可“绑定”,但可以封装成对象管理
Canvas 本身不提供图形实例,所谓“绑定”其实是自己封装类来模拟。比如一个 Ball 类,把 x、y、r、fillStyle 等存为属性,再提供 render(ctx) 方法调用 arc() 绘制:
- 每次重绘都要重新调用绘图命令,不能靠“刷新 DOM”
- 动画场景下,必须用
clearRect()清屏再重绘,否则残留旧帧 - 多个图形共存时,建议统一用数组管理对象,循环调用
render(),避免重复获取ctx - 缩放、旋转、平移等变换要用
save()/restore()隔离状态,否则相互污染
真正难的不是画出一个圆,而是让十个圆各自运动、碰撞检测、响应点击——这些全得手写逻辑,Canvas 只负责最后一笔像素输出。



















