本文讲解如何在点击按钮时,仅处理与该按钮关联的数组对象数据,避免遍历整个数组,提升 cookie clicker 类游戏的可维护性与性能。
本文讲解如何在点击按钮时,仅处理与该按钮关联的数组对象数据,避免遍历整个数组,提升 cookie clicker 类游戏的可维护性与性能。
在开发类似 Cookie Clicker 的增量游戏时,随着可购买建筑(如 Collector、Hunter)数量增加,若为每个按钮单独编写事件处理函数,会导致代码冗余、难以扩展。理想方案是统一管理建筑数据(用数组存储对象),再让每个按钮“知道自己对应哪一项数据”。关键问题在于:
如何在点击事件中精准定位当前按钮所代表的建筑索引?
核心思路是利用 DOM 层级关系反向推导索引。观察 HTML 结构可知,每个 .upgrade 按钮均位于独立的 .soul__shop--buildingcontainer--item 容器内,且这些容器按顺序排列——这与 buildings 数组的索引一一对应。因此,我们可通过以下步骤获取当前按钮对应的建筑对象:
在事件回调中使用 this 指向被点击的按钮;
向上查找其父容器(.soul__shop--buildingcontainer--item);
获取该父容器在其兄弟节点(即所有 .soul__shop--buildingcontainer--item)中的索引位置;
用该索引直接访问 buildings[index],实现精准匹配。
以下是重构后的完整事件绑定逻辑(已适配你的 HTML 结构):
✅
优势说明:
立即学习
“
Java免费学习笔记(深入)
”;
零遍历开销
:不再使用 for 循环检查全部建筑,时间复杂度从 O(n) 降至 O(1);
强耦合保障
:HTML 中按钮顺序与 buildings 数组顺序严格一致,语义清晰、不易出错;
易于扩展
:新增建筑只需在 buildings 数组末尾追加对象,并在 HTML 中添加对应 .upgrade 按钮即可,无需修改事件逻辑。
⚠️
注意事项:
确保 .upgrade 按钮在 DOM 中的顺序与 buildings 数组索引完全对齐(推荐用 forEach 配合 index 参数,而非 querySelectorAll + indexOf,更简洁可靠);
避免在事件中重复查询 DOM 元素(如 document.querySelector(...)),建议将频繁访问的元素缓存为常量;
成本更新后务必同步刷新界面显示(如 .upgrade1-cost),否则玩家无法感知价格变化;
可进一步封装为通用函数(如 purchaseBuilding(index)),便于后续添加音效、动画或成就校验等逻辑。
通过这种基于索引映射的设计,你不仅解决了当前的性能与可维护性问题,还为未来支持数十种建筑打下了坚实基础——真正的“一次编写,持续扩展”。
const upgrades = document.querySelectorAll(".upgrade");
upgrades.forEach((button, index) => {
button.addEventListener("click", function () {
const building = buildings[index]; // ✅ 直接通过循环索引获取对应建筑
if (soulAmount >= building.upgradecost) {
sps += building.sps;
soulAmount -= building.upgradecost;
// 更新 UI
document.querySelector(".souls_amount").textContent = soulAmount;
document.querySelector(".sps").textContent = sps;
// 动态提升升级成本(+20%)
building.upgradecost = Math.round(building.upgradecost * 1.2);
// 同步更新对应按钮旁的成本显示(如 upgrade1-cost / upgrade2-cost)
const costElements = document.querySelectorAll(".upgrade1-cost, .upgrade2-cost");
if (costElements[index]) {
costElements[index].textContent = building.upgradecost;
}
} else {
console.warn(`Not enough souls to buy ${building.name}`);
}
});
});