canvas.clip() 是限制绘制区域而非裁剪图片,需先定义闭合路径再调用,且必须配合 save()/restore() 管理状态,否则裁剪持续生效;矩形裁剪优先用 drawimage() 9参数,非矩形才用 clip()。

canvas.clip() 不是“裁剪图片”,而是限制后续绘制的可见区域;不调用 save() 和 restore(),裁剪会持续影响后面所有绘图操作。
clip() 必须配合路径创建才能生效
调用 clip() 前必须先用 rect()、arc()、beginPath() + lineTo() 等方法定义一个闭合路径。否则裁剪区域为空,后续绘制全部不可见。
- 常见错误:直接写
ctx.clip()后画矩形,结果什么也不显示 - 正确顺序:路径定义 →
ctx.clip()→ 绘制内容(如fillRect()、drawImage()) - 路径是否闭合影响裁剪结果:
closePath()不是必须,但未闭合路径可能导致裁剪行为不符合预期(尤其用evenodd规则时)
裁剪后无法自动恢复,必须手动 save/restore
canvas 的裁剪是“累积”且“不可逆”的——一旦调用 clip(),整个绘图上下文的裁剪区域就缩小了,之后所有绘制都受其约束,直到重置或覆盖。
- 漏掉
save()/restore()是最常被忽略的坑,尤其在循环绘图或叠加多个裁剪区域时 - 推荐写法:
ctx.save(); ctx.rect(...); ctx.clip(); /* 绘制 */ ctx.restore(); - 不用
save()也能重置:把 canvas 宽高重新赋值一次(如canvas.width = canvas.width),但会清空全部内容,代价太大
clip() 的 fillRule 参数影响多边形裁剪逻辑
当路径自交或由多个子路径组成时,clip(fillRule) 决定哪些区域真正被裁剪。默认是 "nonzero",但有时需要显式传参。
-
ctx.clip("nonzero"):按路径方向积分,环绕数非零即保留 -
ctx.clip("evenodd"):点被路径包围奇数次才保留,适合镂空、环形裁剪 - 例如用两个同心圆路径 +
"evenodd",可实现“圆环裁剪”效果 - 浏览器兼容性没问题,但 Safari 旧版本对
"evenodd"支持不稳定,建议实测
想裁剪图片?别只靠 clip(),优先用 drawImage() 参数控制
如果目标是“从一张图里抠出某块区域并显示”,clip() 是绕路方案。真正高效的做法是用 drawImage() 的 9 参数重载,直接指定源区域和目标区域。
- 典型用法:
ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh) - 其中
sx/sy/sw/sh是原图裁剪坐标和尺寸,不依赖路径、不改变上下文状态 - 相比
clip()+drawImage(),它更轻量、无副作用、性能更好 - 只有当你需要“非矩形裁剪”(比如星形遮罩、文字镂空)时,才值得上
clip()
真正难的不是写对 clip(),而是在复杂动画中管理好裁剪状态的嵌套层级——save() 和 restore() 必须严格配对,少一次就可能让后续几十帧全错位。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











