Canvas 的 save() 和 restore() 操作状态栈,仅保存变换矩阵、裁剪路径、样式颜色、线条文本设置及全局合成属性,不保存像素、路径或图像内容;需严格配对使用以避免污染。

Canvas 的 save() 和 restore() 是管理绘图上下文的核心机制,本质是操作一个后进先出(LIFO)的状态栈。它们不保存像素内容,只保存“怎么画”的设置——用得好,能避免样式污染、简化嵌套变换、提升代码可维护性。
哪些上下文属性会被保存和恢复
每次调用 save(),以下全部可变状态会被完整快照并压入栈:
-
变换矩阵:包括所有累积的
translate()、rotate()、scale()、transform()效果(即当前坐标系原点、角度、缩放比例等) -
裁剪路径:由
clip()建立的当前生效裁剪区域(仅路径形状,不含绘制内容) -
样式与颜色:如
fillStyle、strokeStyle、渐变或图案对象 -
线条与文本设置:包括
lineWidth、lineCap、lineJoin、miterLimit、font、textAlign、textBaseline -
全局合成与透明度:如
globalAlpha、globalCompositeOperation、shadow*系列属性
注意:已绘制的图形、canvas 尺寸、像素数据、当前路径(path)本身、图像位图内容均不会被保存。它们只管状态,不管结果。
典型嵌套使用模式
多次 save() 形成嵌套栈,适合模块化绘制逻辑。例如封装一个带旋转+缩放的图标函数,内部自行 save/restore,对外无副作用:
- 第一次
save()→ 初始状态(A) - 执行
rotate(0.2)→ 坐标系旋转 - 第二次
save()→ 状态(B),含旋转 - 执行
scale(1.5, 1.5)→ 再缩放 - 第三次
save()→ 状态(C),含旋转+缩放 - 绘制后调用
restore()两次,依次回到(B)、(A)
漏掉 restore() 会导致后续绘制持续受污染;多调一次则抛出 DOMException: The operation is not supported。
常见实用场景写法
核心原则:在局部变更前 save(),绘制完成后立即 restore(),确保隔离性。
-
旋转文字而不影响其他元素:
ctx.save(); ctx.rotate(-Math.PI / 6); ctx.fillText("Label", x, y); ctx.restore(); -
为一组图形设置独立裁剪区:
ctx.save(); ctx.rect(100, 100, 200, 150); ctx.clip(); ctx.fillRect(80, 80, 240, 180); ctx.restore(); -
临时切换混合模式或半透明效果:
ctx.save(); ctx.globalAlpha = 0.7; ctx.globalCompositeOperation = "overlay"; drawGlowEffect(); ctx.restore();
容易忽略的关键细节
状态栈是轻量级的,但误用会引发隐性 bug:
-
save()不保存当前路径(path)。若你在save()前调用了beginPath()或添加了线段,这些路径操作仍保留在上下文中,restore()不会清空它 - 裁剪路径(
clip())一旦生效,restore()才会取消;未配对的clip()可能导致后续所有绘制被意外裁剪 - 频繁 save/restore 对性能影响极小,但深层嵌套(如循环内反复调用)建议用变量缓存样式值替代,更直观可控
- 调试时可用
console.log(ctx)查看当前部分属性,但无法直接读取栈中历史状态——必须靠逻辑配对保证正确性
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











