在 phaser 中使用 `this.add.dom()` 加载 html ui 后,需在 `create` 阶段而非 `update` 阶段绑定事件监听器;否则每帧重复注册会导致性能问题、事件失效或无响应。
Phaser 的 DOM 对象(如通过 this.add.dom(0, 0).createFromCache('ui') 创建)本质上是将 HTML 元素挂载到 Canvas 旁的
容器中,其生命周期与 Phaser 场景一致。但 DOM 节点的可交互性依赖于正确的时机绑定事件。create() {
// 加载并插入 UI HTML
const domElement = this.add.dom(0, 0).createFromCache('ui');
// 确保 DOM 已渲染完成后再查询元素(推荐加一层安全检查)
this.time.delayedCall(0, () => {
const button = document.querySelector('#dirt');
if (button) {
button.addEventListener('click', () => {
console.log('add dirt');
// ? 可在此触发 Phaser 游戏逻辑,例如:
// this.scene.get('GameScene').addDirt();
});

} else {
console.warn('DOM element #dirt not found in cache');
}
});
}? 提示:delayedCall(0, ...) 是一种轻量级保障 DOM 渲染就绪的方式(尤其当 createFromCache 异步性或渲染时序存在微小延迟时)。也可改用 domElement.node.onload 或 MutationObserver,但对简单 UI,delayedCall(0) 已足够可靠。
// ⚠️ 危险!不要这样做:
update() {
document.querySelector('#dirt').addEventListener('click', () => {
console.log('add dirt'); // 每秒执行约 60 次 → 内存泄漏 + 多重触发
});
}该写法会在每一帧(默认 60 FPS)重复添加监听器,不仅造成严重性能下降,还会导致点击一次触发数十次回调,且旧监听器无法被自动清理,最终 UI 表现“无响应”或行为异常。
const domElement = this.add.dom(0, 0).createFromCache('ui');
domElement.node.querySelector('#dirt').addEventListener('click', () => { /* ... */ });这种方式更明确地限定作用域,避免全局 document 查询可能受其他脚本干扰的风险。
总之,时机决定成败——把事件绑定逻辑放在 create()(或 domElement.once('addedtoscene', ...)),是让 Phaser DOM UI 真正响应用户操作的关键。