Canvas局部刷新的关键是精准识别并仅重绘脏区:计算最小包围矩形、合并多变区域、用clearRect精确擦除、结合离屏缓存静态内容、跳过不可见或未变更绘制。

Canvas局部刷新的关键不是“重绘整个画布”,而是精准识别并仅重绘真正发生变化的区域,同时避免因频繁清空导致的闪烁或性能浪费。
明确脏区(Dirty Region)边界
每次状态变更(如图形移动、颜色更新、文字重写)时,不直接绘制,而是计算其影响范围——即最小包围矩形(Bounding Box)。例如一个半径为10的圆从(50,50)移到(80,60),脏区就是以(40,40)为左上、(90,70)为右下构成的矩形。多个变化可合并为一个联合矩形,用 unionRect 逻辑处理:
- 维护一个
dirtyRect = {x, y, width, height}对象,初始为null - 每次需更新时调用
markDirty(x, y, w, h),将其与当前脏区合并 - 合并逻辑:取 min(x), min(y), max(x+w)−min(x), max(y+h)−min(y)
用 clearRect 精确擦除脏区,而非清空全画布
全量 clearRect(0, 0, canvas.width, canvas.height) 是性能杀手。只清除脏区能显著减少 GPU 填充开销,尤其在大画布或高刷新率场景下:
- 执行重绘前,先
ctx.clearRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height) - 注意:若脏区内有半透明叠加或阴影,单纯 clearRect 可能破坏混合效果——此时应采用“离屏缓存+合成”策略(见下一条)
- 确保脏区坐标已做整数对齐(
Math.floor),避免 sub-pixel 清除引发抗锯齿异常
分层+离屏 Canvas 缓存静态内容
将不变或低频变化的部分(如背景网格、UI 边框、底图)绘制到一个离屏 canvas(offscreenCtx),主画布只负责动态元素。局部刷新时:
立即学习“前端免费学习笔记(深入)”;
- 先将离屏 canvas 对应脏区区域 drawImage 到主画布(覆盖旧内容)
- 再在该区域上绘制最新动态图形
- 这样既保留了静态内容的像素精度,又规避了重复 rasterize 开销
跳过不可见或冗余绘制
在重绘前加轻量级可见性判断和变更比对:
- 检查脏区是否完全在 canvas 可视范围内(
x + w = width || y >= height→ 直接跳过) - 对文本、路径等对象缓存上一帧的序列化快照(如
JSON.stringify({text, font, x, y})),变化才标记脏区 - 动画中若位移增量小于 0.5px 且无缩放/旋转,可忽略本次更新(防过度重绘)
这些方法组合使用,能让局部刷新从“勉强可用”变成“流畅可控”。核心是把“重绘”变成“有依据的最小化操作”,而不是靠 brute-force 清除和重画来掩盖设计缺陷。


















