Canvas 多场景切换需系统性设计,核心是用 visibility + pointer-events 控制显隐、手动暂停动画与音视频、单 canvas 多 scene 分区渲染、显式释放资源、URLSearchParams 同步路由。

Canvas 多场景切换不是简单地 show/hide 元素,而是涉及状态保留、资源清理、渲染隔离和性能控制的系统性设计。核心在于避免 DOM 重排、上下文丢失和内存泄漏,同时保证动画连续、交互准确、音画同步。
用 visibility + pointer-events 管理场景显隐
别用 display: none 切换场景——它会让 canvas 上下文被浏览器回收、video 音画不同步、requestAnimationFrame 失效、CSS 动画重置。正确做法是:
- 设 visibility: hidden:保留布局占位、DOM 结构和动画帧计算能力
- 加 pointer-events: none:阻止鼠标/触摸穿透,避免误触隐藏层
- 在 JS 层主动调用 cancelAnimationFrame 暂停逻辑更新
- 对 audio/video 元素手动执行 pause(),必要时重置 currentTime = 0
单 Canvas + 多 Scene 的 Three.js 方案
多个 canvas → 多个 WebGL 上下文 → 触发浏览器限制(通常 ≤8 个)且无法共享纹理、着色器。推荐统一用一张全屏 canvas,通过“虚拟画布”实现多场景:
- 创建一个全局 THREE.WebGLRenderer,绑定唯一 canvas
- 为每个场景维护独立的 THREE.Scene 和 THREE.Camera
- 用 renderer.setViewport(x, y, width, height) 和 renderer.setScissor(...) 分区渲染
- 按需调用 renderer.render(scene, camera),每次只渲染目标区域
Canvas 资源必须手动释放
反复切换场景时,未清理的 canvas 会持续占用显存和内存,尤其在 SPA 中极易泄漏:
- 2D 上下文:调用 ctx.clearRect(0, 0, canvas.width, canvas.height)
- WebGL 上下文:显式调用 gl.deleteTexture()、gl.deleteBuffer()、gl.deleteProgram() 等
- 移除所有事件监听器:canvas.removeEventListener(...)
- 清空缓冲区:canvas.width = canvas.height = 0(强制重置内部状态)
用 URLSearchParams 同步场景路由
把当前场景标识写入 URL 查询参数,比 class 切换或 state 管理更可靠、可分享、支持浏览器前进/后退:
- 切换场景时更新 history.replaceState 并写入 scene=menu 或 scene=game
- 监听 popstate 事件响应历史导航
- 初始化时解析 new URLSearchParams(location.search).get('scene') 加载对应场景
- 配合 visibility 切换,实现 URL 驱动的无刷新多场景体验


















