如何修复点击按钮时遍历全部建筑对象的JavaScript代码问题
修复Soul Clicker中建筑购买按钮的遍历问题
问题描述
开发类似Cookie Clicker的Soul Clicker游戏时,改用对象数组存储建筑数据优化代码后,点击购买按钮会遍历所有建筑对象,而非仅处理点击对应的建筑,导致逻辑错误。
解决方案
核心是让每个按钮与对应的buildings数组索引绑定,点击时仅处理对应索引的建筑对象:
关键修改点
- 利用
forEach的第二个参数获取按钮对应的数组索引,避免遍历所有建筑 - 修复变量名冲突(原代码中
forEach参数和循环变量都用i,导致逻辑混乱) - 点击事件中直接通过索引定位目标建筑,只执行该建筑的购买逻辑
修改后的JavaScript代码
let soulAmount = 0; let soulAddition = 1; let grabSps = document.querySelector(".sps").innerHTML; let sps = parseInt(grabSps); let upgrade1GOT = false; let upgrade2GOT = false; let buildings = [ { "name": "Collector", "upgradecost": 10, "sps": 1 }, { "name": "Hunter", "upgradecost": 100, "sps": 5 } ]; let upgrades = document.querySelectorAll(".upgrade"); // 关键修改:使用forEach的索引参数绑定对应建筑 upgrades.forEach(function (button, index) { button.addEventListener("click", function () { const building = buildings[index]; // 只处理当前点击按钮对应的建筑 if (soulAmount >= building.upgradecost) { sps += building.sps; soulAmount -= building.upgradecost; document.querySelector(".souls_amount").innerHTML = soulAmount; document.querySelector(".sps").innerHTML = sps; // 升级成本提升20% building.upgradecost = Math.round(building.upgradecost * 1.2); console.log(building.upgradecost); } }) }); window.setInterval(function() { document.querySelector(".souls_amount").innerHTML = soulAmount; document.querySelector(".upgrade1-cost").innerHTML = buildings[0].upgradecost; document.querySelector(".upgrade2-cost").innerHTML = buildings[1].upgradecost; validateSoul(); }, 1); function validateSoul(){ if(soulAmount >= 10 && soulAmount <= 19 && upgrade1GOT == false){ document.getElementById("collect100").style.display = "block" document.getElementById("collect100").disabled = true; } else if (soulAmount >= 20 && upgrade1GOT == false){ document.getElementById("collect100").disabled = false; } if(soulAmount >= 100 && soulAmount <= 199 && upgrade2GOT == false){ document.getElementById("collect1000").style.display = "block" document.getElementById("collect1000").disabled = true; } else if (soulAmount >= 200 && upgrade2GOT == false){ document.getElementById("collect1000").disabled = false; } // 优化按钮状态判断,利用索引循环简化 upgrades.forEach((button, index) => { button.disabled = soulAmount < buildings[index].upgradecost; // 处理Hunter的显示逻辑 if(index === 1 && !button.disabled){ document.querySelector(".soul__shop--name").innerHTML = buildings[1].name; } }); } function getSoul() { soulAmount += soulAddition; document.querySelector(".souls_amount").innerHTML = soulAmount; return soulAmount; } // 补充缺失的成就函数(原HTML中调用但未定义) function achievement1() { upgrade1GOT = true; document.getElementById("collect100").style.display = "none"; // 可添加成就奖励逻辑,比如提升soulAddition } function achievement2() { upgrade2GOT = true; document.getElementById("collect1000").style.display = "none"; // 可添加成就奖励逻辑 }
关键知识点说明
forEach的参数:querySelectorAll返回的NodeList调用forEach时,第二个参数是当前元素的索引,可用来关联数组中的对应对象- 变量作用域:原代码中
forEach的参数名和循环变量都用i,导致变量冲突覆盖,使用不同命名(如button、index)可避免此问题 - 事件绑定上下文:通过在
forEach中绑定索引,点击事件能直接获取到对应建筑,无需遍历整个数组,提升性能并避免逻辑错误
内容的提问来源于stack exchange,提问作者Burakkuboido
相关产品推荐
相关产品推荐

