Phaser在update函数调用getChildByName无法正确获取DOM表单值如何解决
问题原因
这个问题的核心是浏览器原生表单的默认行为和Phaser键盘事件的触发时序冲突:
- 当你在表单输入框内按下回车键时,浏览器会先触发表单的隐式提交默认行为,自动清空/重置表单内容
- Phaser的
update循环中键盘事件的触发时机晚于原生DOM的提交事件,所以你调用validateFormIdentity时拿到的是表单被重置后的空值 - 而点击提交按钮的逻辑绑定在原生DOM的
onclick事件上,触发时还没有执行表单默认重置,所以能正常取值
解决方案
直接在create阶段拦截表单的默认提交行为,同时可以优化回车键监听逻辑,不需要写在update里占用帧循环资源,修改后代码如下:
export default class Identity extends Phaser.Scene { constructor() { super({ key: "ABC" }); this.enterKeyIdentity; console.log("constructor ....") } preload() { this.load.html("identity_form", "/assets/forms/Unlock1/identity.html"); } create() { this.formInput = this.add.dom(0, 0).createFromCache("identity_form"); this.formInput.originX = 0; this.formInput.originY = 0; // 新增:拦截表单默认提交行为,防止回车自动清空表单 const formElement = this.formInput.node; formElement.addEventListener('submit', (e) => { e.preventDefault(); this.validateFormIdentity(); }); // 原有点击提交逻辑可保留也可删除,上面的submit事件已经覆盖了按钮点击提交场景 this.formInput.getChildByName("submit").onclick = () => { this.validateFormIdentity(); }; // 如果需要额外监听画布聚焦时的回车键提交,可以保留下面的逻辑,不需要直接删除即可 this.enterKeyIdentity = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.ENTER); this.enterKeyIdentity.on('down', () => { // 只有当焦点不在表单输入框内时才触发,避免重复校验 if (!['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) { this.validateFormIdentity(); } }); } // 可以删除update里的监听逻辑,已经用事件回调替代了 // update () { // if(Phaser.Input.Keyboard.JustDown(this.enterKeyIdentity)) { // console.log("pressed down"); // this.validateFormIdentity(); // } //} validateFormIdentity = () => { console.log("submit called") // 也可以直接用原生DOM取值,稳定性更高 const formData = new FormData(this.formInput.node); let city1 = formData.get('city1'); let city2 = formData.get('city2'); let city3 = formData.get('city3'); console.log(city1, city2, city3) } }
补充说明
- 直接拦截表单的
submit事件后,不管是按回车还是点提交按钮,都会触发校验逻辑,不需要单独写两套监听 - 用原生
FormData取值比Phaser封装的getChildByName兼容性更好,也避免了Phaser DOM缓存不同步的问题
内容的提问来源于stack exchange,提问作者Osama Bin Saleem
相关产品推荐
相关产品推荐

