canvas 不参与响应式绑定,其性能优势源于跳过 dom 渲染流水线而手动绘图;适用于高频重绘、大量简单元素场景,但牺牲可访问性、交互支持与维护性。

Canvas 渲染和 DOM 绑定性能根本不是同一类问题
直接说结论:Canvas 本身不参与“绑定”(如 Vue 的响应式更新、React 的 state 同步),它只是个位图绘图表面。所谓“改善绑定性能”,其实是绕开了绑定——把原本靠频繁 DOM 更新(比如 v-for 渲染几百个 div)驱动的交互,换成用 Canvas 手动控制像素绘制。这不是优化绑定,是替换绑定。
什么时候用 Canvas 真能“感觉更快”
典型场景:需要高频重绘(60fps)、元素数量大(>200)、样式简单(无复杂布局/事件冒泡需求)。
- 地图缩放平移(Leaflet 开启
preferCanvas: true) - 实时波形图(每 16ms 重绘一条线,DOM 下用
svg:path或div会卡顿) - 粒子系统(500+ 粒子位置每帧更新)
关键不是 Canvas 多快,而是它跳过了:浏览器样式计算 → 布局(Layout)→ 绘制(Paint)→ 合成(Composite)整条流水线,只走最后的“上传纹理 + GPU 绘制”这一步。
别踩坑:Canvas 不是万能加速器
常见误用:
- 给每个按钮都画在 Canvas 里 → 失去
button的可访问性、默认 focus/键盘行为、CSS 伪类(:hover)支持 - 监听
canvas的click后手动做坐标换算判断点击了哪个“虚拟按钮” → 逻辑爆炸,且无法被屏幕阅读器识别 - 用
ctx.fillText()渲染长段落文字 → 缺少自动换行、字距调整、字体回退,性能反而不如div+ CSS - 在 Canvas 里模拟表格滚动 → 滚动事件、滚动条、惯性、touch 适配全得自己写,比
overflow: auto贵十倍维护成本
一个对比代码:DOM 列表 vs Canvas 绘制相同数据
假设有 300 个数字要动态更新(比如传感器读数):
// DOM 方式(Vue 示例)—— 每次更新触发 300 次 VNode diff + 元素 patch
<div v-for="n in numbers" :key="n">{{ n }}</div>
<p>// Canvas 方式(纯 JS)—— 只清空再重绘一遍文本
const canvas = document.getElementById('chart');
const ctx = canvas.getContext('2d');
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
numbers.forEach((n, i) => {
ctx.fillText(n, 10, 20 + i * 16); // 一行一个数字
});
}
// render() 每秒调用 60 次,CPU 占用稳定;DOM 版本在低端机上会掉帧
</p>
注意:clearRect 和 fillText 的开销远低于创建/更新 300 个 DOM 节点。但代价是你不能再用 document.querySelector('.number-123') 去拿某个值——它根本不存在于 DOM 树里。
Canvas 的“性能优势”永远附带交互与可维护性折损。要不要换,取决于你是否真的在瓶颈处:是卡在渲染,还是卡在事件响应、数据解析、网络请求?先用 Chrome DevTools 的 Performance 面板录一段,看火焰图里 Recalculate Style 和 Layout 占多少时间——再决定动不动 Canvas。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











