JS石头剪刀布开发如何等待按钮点击后更新playerValue
石头剪刀布游戏playerValue不更新问题解决方案
问题根因
开发石头剪刀布游戏时,全局定义的playerValue初始值为0,预期点击对应按钮时将其更新为对应数值(石头=1、剪刀=2、布=3),但实际运行时playerValue始终为0。
原有相关代码如下:
事件绑定逻辑:
//register button click and: function player_choose_value(){ //check which button has been clicked -> rock 1, scissor 2 or paper 3 btnRock.addEventListener("click", () =>{ playerValue = 1; }); btnScissor.addEventListener("click", () =>{ playerValue = 2; }); btnPaper.addEventListener("click", () =>{ playerValue = 3; }); }
回合执行逻辑:
function play_round(){ let computerValue = computer_choose_value(); player_choose_value();//is always zero console.log(playerValue); won_tie_lost(computerValue, playerValue); }
问题出在两个地方:
addEventListener是异步非阻塞API,调用后只会把回调注册到事件队列,不会阻塞当前代码执行,player_choose_value运行完立刻就会执行后续取值逻辑,此时用户还没来得及点击按钮,值自然保持初始0- 事件绑定逻辑放在回合函数里,每执行一次回合就会给按钮叠加一层新的事件监听,玩的次数越多,单次点击触发的回调就越多,属于绑定时机错误。
实现方案
核心思路是:不要在回合执行流程里绑定事件,把「等待用户点击」的异步逻辑和后续同步的判定逻辑做衔接,两种常用实现方式如下:
方案1:回调触发(实现简单,适合小型项目)
页面初始化时只绑定一次按钮事件,用户点击拿到选择值后,直接在点击回调里触发后续回合判定即可,不需要额外封装异步逻辑。
修改后代码:
// 全局定义玩家选择值 let playerValue = 0; // 页面加载完成后只调用一次,绑定按钮事件 function initBtnEvent(){ btnRock.addEventListener("click", () =>{ playerValue = 1; // 拿到选择后直接执行回合判定 runRound(); }); btnScissor.addEventListener("click", () =>{ playerValue = 2; runRound(); }); btnPaper.addEventListener("click", () =>{ playerValue = 3; runRound(); }); } // 抽离纯回合判定逻辑,不需要再包含事件绑定 function runRound(){ const computerValue = computer_choose_value(); console.log(playerValue); won_tie_lost(computerValue, playerValue); } // 页面初始化时执行绑定 initBtnEvent();
小提示:如果需要防止玩家在回合结算过程中重复点击,可以在
runRound执行时给按钮加禁用状态,结算完成后再恢复。
方案2:Promise封装(逻辑清晰,适合后续扩展)
如果不想把判定逻辑散落在各个点击回调里,可以用Promise封装等待用户选择的逻辑,配合async/await实现类同步的代码写法,逻辑流和自然思考顺序一致,也不会出现重复绑定事件的问题。
修改后代码:
let playerValue = 0; // 封装等待玩家选择的异步方法 function waitPlayerChoose(){ return new Promise(resolve => { // 定义单次点击的处理函数 const handleRock = () => { clearListener(); resolve(1); } const handleScissor = () => { clearListener(); resolve(2); } const handlePaper = () => { clearListener(); resolve(3); } // 点击后统一移除临时监听,避免重复触发 const clearListener = () => { btnRock.removeEventListener("click", handleRock); btnScissor.removeEventListener("click", handleScissor); btnPaper.removeEventListener("click", handlePaper); } // 绑定临时监听 btnRock.addEventListener("click", handleRock); btnScissor.addEventListener("click", handleScissor); btnPaper.addEventListener("click", handlePaper); }) } // 回合函数标记为async,就可以用await等待用户操作 async function playRound(){ // 等待玩家点击,拿到选择值后再往下执行 playerValue = await waitPlayerChoose(); const computerValue = computer_choose_value(); console.log(playerValue); won_tie_lost(computerValue, playerValue); // 结算完成后开启下一轮等待 playRound(); } // 启动第一回合 playRound();
内容的提问来源于stack exchange,提问作者morloq
相关产品推荐
相关产品推荐

