在类中设置mouseup事件:将页面事件监听代码迁移至类的问题
问题分析与解决方案
你遇到的核心问题是类方法中事件回调的this指向错误,导致docMouseUp方法无法正确访问类实例的属性(比如this.frame),甚至可能根本无法正常触发预期逻辑。
为什么会出错?
在setListener方法里的mousedown回调是普通函数:
this.frame.on("mousedown", function(evt) { // 这里的this指向的是触发mousedown事件的DOM元素,不是MyRectangle类的实例! $(document).bind("mouseup", this.docMouseUp); });
当你在这里写this.docMouseUp时,this已经不是类实例了,而是当前的DOM元素,所以this.docMouseUp大概率是undefined;就算你之前定义了docMouseUp方法,也会因为绑定的上下文错误导致执行时出问题。
三种修复方案
方案1:使用箭头函数(最简洁推荐)
箭头函数不会创建自己的this,它的this继承自外层作用域(也就是类实例),这样就能正确访问到this.docMouseUp:
class MyRectangle { constructor(elementId) { this.frame = $("#" + elementId); this.setListener(); } setListener() { this.frame.on("mousedown", (evt) => { // 改成箭头函数 evt.preventDefault(); console.log("MOUSE DOWN" + " " + evt.pageX + ", " + evt.pageY); // 这里的this是MyRectangle实例,所以this.docMouseUp正确指向类方法 $(document).on("mouseup", this.docMouseUp); }); } docMouseUp(evt) { evt.preventDefault(); console.log("MOUSE UP" + " " + evt.pageX + ", " + evt.pageY); // 记得解绑mouseup事件,避免重复绑定 $(document).off("mouseup", this.docMouseUp); } }
方案2:提前保存类实例的引用
在回调外部把this存到变量(比如self),然后在回调里用这个变量访问类实例:
class MyRectangle { constructor(elementId) { this.frame = $("#" + elementId); this.setListener(); } setListener() { const self = this; // 保存类实例的引用 this.frame.on("mousedown", function(evt) { evt.preventDefault(); console.log("MOUSE DOWN" + " " + evt.pageX + ", " + evt.pageY); // 用self访问类实例的docMouseUp方法 $(document).on("mouseup", self.docMouseUp); }); } docMouseUp(evt) { evt.preventDefault(); console.log("MOUSE UP" + " " + evt.pageX + ", " + evt.pageY); $(document).off("mouseup", this.docMouseUp); } }
方案3:使用bind强制绑定this
可以在绑定事件时,用bind把docMouseUp的this强制绑定到类实例:
class MyRectangle { constructor(elementId) { this.frame = $("#" + elementId); // 提前绑定docMouseUp的this,避免每次绑定事件都调用bind this.docMouseUp = this.docMouseUp.bind(this); this.setListener(); } setListener() { this.frame.on("mousedown", function(evt) { evt.preventDefault(); console.log("MOUSE DOWN" + " " + evt.pageX + ", " + evt.pageY); $(document).on("mouseup", this.docMouseUp); }.bind(this)); // 把mousedown回调的this也绑定到类实例 } docMouseUp(evt) { evt.preventDefault(); console.log("MOUSE UP" + " " + evt.pageX + ", " + evt.pageY); $(document).off("mouseup", this.docMouseUp); } }
额外注意点
- 把
bind换成on/off:jQuery推荐用on和off替代bind/unbind,后者已经是过时方法了。 - 一定要在
mouseup触发后解绑事件:如果不解绑,每次mousedown都会绑定一个新的mouseup事件,多次点击后会触发多次docMouseUp,造成逻辑混乱。
内容的提问来源于stack exchange,提问作者Dusan
相关产品推荐
相关产品推荐

