canvas的save()和restore()通过后进先出状态栈保存并还原变换矩阵、裁剪路径、样式颜色、线条文本设置及全局合成属性,不保存像素、路径或图像内容,须严格配对使用以防污染。

Canvas 绘图上下文本身不支持自动持久化,所谓“持久化管理”实际是指对绘图状态(state)的可靠保存与恢复,核心靠 save() 和 restore() 构建的状态栈机制实现——它不是保存像素或图形内容,而是保存“怎么画”的配置快照。
哪些状态会被真正保存
每次调用 save(),以下上下文属性会被完整压栈:
-
变换矩阵:所有累积的
translate()、rotate()、scale()、transform()效果,即当前坐标系原点、旋转角度、缩放比例等 -
裁剪路径:由
clip()定义的生效区域(仅路径形状,不含绘制结果) -
样式与颜色:包括
fillStyle、strokeStyle、渐变对象、图案填充 -
线条与文本设置:如
lineWidth、lineCap、font、textAlign、textBaseline -
全局合成与透明度:如
globalAlpha、globalCompositeOperation、阴影相关属性(shadowOffsetX等)
注意:save() 不保存已绘制的像素、当前路径(Path)、canvas 尺寸、图像位图或任何绘图结果——它只管“状态”,不管“画面”。
为什么必须配对使用
状态栈是后进先出(LIFO)结构,restore() 总是弹出最近一次 save() 的快照并还原上下文。漏掉 restore() 会导致后续所有绘制持续受污染(比如意外旋转、半透明叠加);多调一次则抛出 DOMException 错误。典型嵌套示例如下:
- 初始状态 →
save()(A) - 执行
rotate(0.3)→save()(B) - 执行
scale(2, 2)→save()(C) - 绘制完成后连续两次
restore(),依次回到 B、A 状态
实用场景中的写法习惯
关键原则:在局部变更前 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.6; ctx.globalCompositeOperation = "multiply"; drawGlow(); ctx.restore();
容易被忽略的细节
这些点看似微小,却常引发隐性 bug:
-
save()不保存当前路径 —— 若你在save()前调用了beginPath()或添加了线段,restore()后路径仍处于未闭合或已定义状态,需手动重置 - 状态栈轻量但不可无限增长,深度嵌套时建议用函数封装并严格配对,避免栈溢出风险
- canvas 尺寸(
width/height属性)和像素缓冲区属于 DOM 属性,不属于上下文状态,save()/restore()对其完全无影响
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











