更新、更改或删除/重置Javascript事件侦听器

更新、更改或删除/重置Javascript事件侦听器,javascript,html,Javascript,Html,好的,我正在开发一个小的html5画布绘图库,我有一个小问题,下面是代码(fiddle): 我在这里试图实现的是:当我调用drawr.draw()时第二个(或第三个等)以使其覆盖上一个功能。我该怎么做?正如您在我的示例中所看到的,每个实例同时运行 请随意编辑、更新、删除、为错误代码对我大喊大叫等。调用addEventListener将覆盖上一个,或者调用removeEventListener将删除侦听器,仅当为该事件类型指定的处理程序函数严格相等时。一个匿名函数,即使在词汇上完全相同,也不等于在

好的,我正在开发一个小的html5画布绘图库,我有一个小问题,下面是代码(fiddle):

我在这里试图实现的是:当我调用
drawr.draw()时第二个(或第三个等)以使其覆盖上一个功能。我该怎么做?正如您在我的示例中所看到的,每个实例同时运行


请随意编辑、更新、删除、为错误代码对我大喊大叫等。

调用
addEventListener
将覆盖上一个,或者调用
removeEventListener
将删除侦听器,仅当为该事件类型指定的处理程序函数严格相等时。一个匿名函数,即使在词汇上完全相同,也不等于在单独执行该方法期间创建的第二个匿名函数

这里有一个想法:将处理程序定义为闭包中的一个单独函数,如下所示:

obj = function() {
    function handler() { /* handle the click; "this" is the element */ }

    return {
        draw: function() {
            this.elt.addEventListener('click', handler);
            //draw a bunch of stuff
        },

        undraw: function() {
            this.elt.removeEventListener('click', handler);
            //undraw a bunch of stuff
        }

    };
}();
现在,由于
处理程序
始终严格等于自身,因此
removeEventListener
将成功删除该处理程序。或者,第二个
addEventListener
将不起任何作用(只需将当前处理程序留在原位)

但是,
handler
无法访问对象的
this
;它将被调用,事件的目标元素作为它的
this
。为了将对象的
this
放入事件处理程序,您可能会尝试

this.elt.addEventListener('click', handler.bind(this));
但这将无法实现您想要的功能,因为每次调用该方法时,
handler.bind(this)
的值都不同,因此您将再次使用冗余的事件处理程序,或者
removeEventListener
s,但它们不起作用

如果您确实希望对象的
this
在处理程序中,并且不知道如何从事件中检索它,您可以在一些
init
函数中初始化
处理程序的绑定版本:

obj = {
    handler: function(event) { /* handle the click; "this" is the object */ },

    draw: function() {
        this.elt.addEventListener('click', this.handler);
        //draw a bunch of stuff
    },

    undraw: function() {
        this.elt.removeEventListener('click', this.handler);
        //undraw a bunch of stuff
    },

    init: function() {
        this.handler = this.handler.bind(this);
        return this;
    }
}.init();
由于
这个.handler
始终与自身相同,因此它可以按预期工作

使用
EventListener
解决此问题的一种更优雅的方法是将带有接口的对象传递给
addEventListener
,而不是传递给函数,接口是实现特殊命名的
handleEvent
方法的任何对象,该方法可以是“this”对象本身,因此您可以执行以下操作:

obj = {
    handleEvent: function(event) {
        // "this" is the  object
        if (event.type === 'click') {
            // do stuff
        }
    },
    draw: function() {
        this.elt.addEventListener('click', this);
    },
    undraw: function() {
        this.elt.removeEventListener('click', this);
    }
};
请注意,
正在传递给
addEventListener
。换句话说,我们正在传递对象本身,在它的化身中作为
EventListener
的实例,因为它已经实现了
handleEvent
handleEvent
是对象的一个成熟方法,因此可以完全访问其所有方法和属性,并且由于
与自身相同,因此添加、再次添加和删除行为可以按照您的需要工作

我不认为这种方法使用得太多,但它可以使事件处理更加简化,特别是如果在其周围添加一些糖分,例如安排单独的方法来处理每个事件类型:

obj = {
    handleEvent: function(event) {
        return this[event.type](event); // dispatch to method with name of event
    },
    click: function(event) {
        // handle click; "this" is obj
    },

    draw: function() { 
        this.elt.addEventListener('click', this); 
    },
    undraw: function() {
        this.elt.removeEventListener('click', this);
    }
};

好吧,我来试试。我会让你知道事情的进展!我想用的方式最合乎逻辑吗?使用事件处理程序等?我应该考虑一种不同的方法吗?不太确定你要问的是什么——如果你想处理事件,你需要事件处理程序。我喜欢第一个解决方案,在你标题中的事件听者认为我的方法是我试图得到的。我还没有机会尝试。如果一切顺利,我会回来给你绿色支票。同时,为你所有的时间和努力+1!!好的,我还有一个后续问题:在您的帮助下,(和MDN文档),我成功地创建了覆盖自己的事件侦听器。但是,我希望放弃原来的侦听器,并能够继续使用新的侦听器。根据MDN,忽略第二个侦听器:
如果在同一个EventTarget上使用相同的参数注册了多个相同的EventListener,则会丢弃重复的实例….
obj = {
    handleEvent: function(event) {
        return this[event.type](event); // dispatch to method with name of event
    },
    click: function(event) {
        // handle click; "this" is obj
    },

    draw: function() { 
        this.elt.addEventListener('click', this); 
    },
    undraw: function() {
        this.elt.removeEventListener('click', this);
    }
};