Canvas层级管理本质是按z值排序绘图顺序:将含z属性的对象存入数组,渲染前sort后依次绘制;需为透明度和混合模式单独设置并重置全局状态;文字与描边/填充均须同级参与z排序;z值变更时仅重排数组并重绘。

Canvas 本身没有图层或 z-index 概念,所谓“层级管理”,本质是控制绘图顺序:后绘制的内容覆盖先绘制的。最直接、稳定且轻量的方式,就是用数组存储所有可绘制对象,按 z 值排序后再依次调用 ctx.drawImage() 或 ctx.fillRect() 等命令。
给每个图形加 z 属性,统一参与排序
不要靠代码书写顺序或 DOM 层叠来“猜”谁在前谁在后。为每个图形对象显式定义 z(或 zIndex)字段,例如:
{ type: 'rect', x: 10, y: 20, width: 80, height: 40, z: 1 }{ type: 'text', content: '标题', x: 50, y: 100, z: 3 }{ type: 'image', src: 'icon.png', x: 200, y: 150, z: 2, opacity: 0.8 }
所有对象放进一个数组(如 sceneObjects = []),渲染前执行 sceneObjects.sort((a, b) => a.z - b.z),确保 z 小的先画、z 大的后画。
透明度、混合模式也要纳入排序逻辑
globalAlpha 和 globalCompositeOperation 是全局状态,不是图形自带属性。若某图形需半透明或叠加效果(如 'multiply'),必须在它被绘制前设置,否则会影响后续图形:
- 遍历排序后的数组时,对每个对象单独设置
ctx.globalAlpha = obj.opacity || 1 - 再设
ctx.globalCompositeOperation = obj.blendMode || 'source-over' - 完成绘制后,建议立即重置为默认值(
ctx.globalAlpha = 1,ctx.globalCompositeOperation = 'source-over'),避免污染下一项
文字与描边/填充要同级参与排序
文字不是“自动浮在顶层”的元素。如果一段文字 z: 4,而它下方有个 z: 5 的遮罩矩形,文字就会被盖住。同样,带描边的图形(如 strokeStyle + stroke())和填充图形(fillStyle + fill())若属于不同对象,也必须各自拥有 z 值并参与统一排序——不能假设“描边一定比填充靠前”。
动态更新时只重排数组,不重建 Canvas
当某个图形的 z 值改变(比如用户拖拽图层条调整顺序),只需修改该对象的 z 字段,再重新调用 sort(),然后整帧重绘即可。无需创建新 Canvas、也不必维护多个离屏缓冲——只要对象数量不过千,这种纯数组排序+顺序绘制的方式性能足够好,逻辑也清晰可控。


















