Cookie Clicker类游戏:模板HTML元素绑定类实例onclick方法问题
问题根源
你遇到的核心问题是:普通函数作为事件回调时,this会指向触发事件的DOM元素(这里是按钮),而非你期望的Servant类实例,所以调用this.hire()会报错——因为按钮对象根本没有hire方法。
直接修复方案
方案1:使用箭头函数
箭头函数不会绑定自身的this,它会继承外层作用域的this(也就是unlock方法中的Servant实例)。修改按钮点击绑定代码:
clone.querySelector(".hire-button").onclick = () => { this.hire(); // 此处this即为当前Servant实例 };
方案2:用bind()强制绑定this
通过bind()方法把回调函数的this固定为当前Servant实例:
clone.querySelector(".hire-button").onclick = function () { this.hire(); }.bind(this); // 绑定Servant实例到回调的this
方案3:缓存实例到变量
在unlock方法里先把实例存到变量,回调中直接使用该变量访问实例:
const self = this; // 缓存当前Servant实例 clone.querySelector(".hire-button").onclick = function () { self.hire(); // 通过self调用实例方法 };
原方案的不足与优化替代方案
原方案存在的问题
- 每个仆人按钮单独绑定事件,当仆人数量增多时,会累积大量DOM事件监听,影响性能。
update_gui方法每次通过document.querySelector重复查询DOM元素,效率低下。
优化方案:事件委托+DOM元素缓存
步骤1:缓存DOM元素到Servant实例
在unlock方法中把创建的DOM元素存入实例属性,后续更新UI直接复用:
unlock() { this.unlocked = true; const template = document.querySelector("#servant-template"); const clone = template.content.firstElementChild.cloneNode(true); clone.id = `servant-${this.name}`; this.domElement = clone; // 缓存DOM元素到实例 servants_gui.appendChild(clone); this.update_gui(); } update_gui() { if (!this.unlocked) return; // 直接使用缓存的domElement,避免重复查询 this.domElement.querySelector(".count-span").textContent = this.count; this.domElement.querySelector(".name-span").textContent = this.name; this.domElement.querySelector(".value-span").textContent = this.value; this.domElement.querySelector(".hire-cost").textContent = this.cost; }
注:用textContent替代innerHTML更安全,能避免XSS风险,同时性能更优。
步骤2:事件委托统一处理点击
在父元素<ul id="servants">上绑定一次点击事件,通过事件冒泡判断点击目标,再关联对应Servant实例:
// 初始化时绑定一次事件委托即可 document.querySelector("#servants").addEventListener("click", (e) => { if (e.target.classList.contains("hire-button")) { // 找到对应的li元素,提取仆人名称 const li = e.target.closest("li"); const servantName = li.id.replace("servant-", ""); // 匹配对应的Servant实例 const servant = servants.find(s => s.name === servantName); if (servant) { servant.hire(); } } });
这种方式无需给每个按钮单独绑定事件,新增仆人时也无需额外处理,性能更高效。
内容的提问来源于stack exchange,提问作者Ter Maxima
相关产品推荐
相关产品推荐

