使用JS Prototype停止观察事件不能使用.bind(this)

时间:2010-04-02 16:20:54

标签: javascript javascript-events prototypejs

我正在开发一个基于Prototype库的Javascript类。这个类需要观察一个事件来执行拖动操作(当前的拖放控件不适合这种情况),但我遇到了让它停止观察事件的问题。

以下是导致此问题的示例:

var TestClass = Class.create({
    initialize: function(element) {
        this.element = element;
        Event.observe(element, 'mousedown', function() {
            Event.observe(window, 'mousemove', this.updateDrag.bind(this));
            Event.observe(window, 'mouseup', this.stopDrag.bind(this));
        });
    },
    updateDrag: function(event) {
        var x = Event.pointerX(event);
        var y = Event.pointerY(event);
        this.element.style.top = y + 'px';
        this.element.style.left = x + 'px';
    },
    stopDrag: function(event) {
        console.log("stopping drag");
        Event.stopObserving(window, 'mousemove', this.updateDrag.bind(this));
        Event.stopObserving(window, 'mouseup', this.stopDrag.bind(this));
    }
});

如果没有.bind(this),那么this.element是未定义的,但是使用它时,事件不会被停止观察(虽然控制台输出确实发生了)。

1 个答案:

答案 0 :(得分:4)

每次调用它时,

bind都会返回一个新的函数引用(这是它的工作:-)),如果函数引用是===匹配,stopObserving将只取消处理程序

要解决此问题,请记住绑定为属性的事件处理程序,然后将该属性与stopObserving一起使用。或者,如果您负责该元素,则可以通过简单地省略第三个参数来取消mousemovemouseup事件的所有处理程序。 (有关将参数留给stopObserving)的更多信息,请参阅链接的文档。

所以:

initialize: function(element) {
    this.element = element;
    this.boundUpdateDrag = this.updateDrag.bind(this);
    this.boundStopDrag = this.stopDrag.bind(this);
    Event.observe(element, 'mousedown', function() {
        // Off-topic, but see note at end of answer, unrelated bug here
        Event.observe(window, 'mousemove', this.boundUpdateDrag);
        Event.observe(window, 'mouseup', this.boundStopDrag);
    });
},
stopDrag: function(event) {
    console.log("stopping drag");
    Event.stopObserving(window, 'mousemove', this.boundUpdateDrag);
    Event.stopObserving(window, 'mouseup', this.boundStopDrag);
}

或者只是

stopDrag: function(event) {
    console.log("stopping drag");
    Event.stopObserving(window, 'mousemove');
    Event.stopObserving(window, 'mouseup');
}

但请注意,后者删除了该元素上那些事件的所有处理程序(嗯,通过Prototype连接的那些)。


偏离主题,但请注意您的initialize函数中存在错误:它在this的处理程序中使用mousedown,但未确保this已设置它应该被设置为什么。您需要绑定该匿名函数,或使用initialize中的变量来利用匿名函数是闭包的事实。

所以要么再次使用bind:

initialize: function(element) {
    this.element = element;
    this.boundUpdateDrag = this.updateDrag.bind(this);
    this.boundStopDrag = this.stopDrag.bind(this);
    Event.observe(element, 'mousedown', (function() {
        Event.observe(window, 'mousemove', this.boundUpdateDrag);
        Event.observe(window, 'mouseup', this.boundStopDrag);
    }).bind(this));
},

或者使用你正在定义闭包的事实:

initialize: function(element) {
    var self;

    self = this; // Remember 'this' on a variable that will be in scope for the closure
    this.element = element;
    this.boundUpdateDrag = this.updateDrag.bind(this);
    this.boundStopDrag = this.stopDrag.bind(this);
    Event.observe(element, 'mousedown', function() {
        // Note we're using 'self' rather than 'this'
        Event.observe(window, 'mousemove', self.boundUpdateDrag);
        Event.observe(window, 'mouseup', self.boundStopDrag);
    });
},