javascript - 更新或更改或删除/重置 Javascript 事件监听器

标签 javascript html

好的,所以我正在开发一个小型 html5 canvas 绘图库,但我遇到了一个小问题,这是代码(下面的 fiddle ):

var drawr = {
init: function (canvas_id, canvasWidth, canvasHeight) { //height & width are optional
    this.canvas_id = document.getElementById(canvas_id);
    this.canvasWidth = canvasWidth;
    this.canvasHeight = canvasHeight;
    this.context = this.canvas_id.getContext('2d');

    if (canvasWidth) {
        this.canvas_id.width = canvasWidth;
    }

    if (canvasHeight) {
        this.canvas_id.height = canvasHeight;
    }

},

//magic line drawing function
ctx: function (a, b, x, y, dLineColor, dLineWidth) { //lineWidth & lineColor are optional; defaults are 1px & 'black'
    this.context.lineJoin = 'round';
    this.context.beginPath();
    this.context.moveTo(a, b);
    this.context.lineTo(x, y);
    this.context.closePath();
    this.context.strokeStyle = dLineColor;
    this.context.lineWidth = dLineWidth;
    this.context.stroke();

},

//destroy event handlers to prevent drawing
destroy: function () {
    //destroy event handlers

},

draw: function (lineColor, lineWidth) {
    //create some utilities for draw function to use
    var localPen = {};
    var drawing = false;
    var canvasPos = {
        x: this.canvas_id.offsetLeft,
        y: this.canvas_id.offsetTop
    }

    //initiate event handlers
    this.canvas_id.addEventListener('mousedown', addDraw, false);

    function addDraw(e) {
        drawing = true;
        console.log(drawing);
        localPen.x = e.pageX - canvasPos.x;
        localPen.y = e.pageY - canvasPos.y;
    };


    this.canvas_id.addEventListener('mousemove', function (e) {
        var drawTo = {
            x: e.pageX - canvasPos.x,
            y: e.pageY - canvasPos.y
        }
        if (drawing) {
            drawr.ctx(localPen.x, localPen.y, drawTo.x, drawTo.y, lineColor, lineWidth);
        }

        localPen.x = drawTo.x;
        localPen.y = drawTo.y;

    });

    this.canvas_id.addEventListener('mouseup', function (e) {
        drawing = false;
    });

    this.canvas_id.addEventListener('mouseleave', function (e) {
        drawing = false;
    });
    }

}

    drawr.init('my_canvas');
    drawr.draw('red', 10);
    drawr.draw('blue', 5);

我在这里想要完成的是:当我第二次(或第三次等)调用 drawr.draw(); 时,它会覆盖之前的函数。我该怎么办?正如你在我的 fiddle 中看到的那样每个实例同时运行。

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

最佳答案

只有当为该事件类型指定的处理函数是>严格相等。一个匿名函数,即使在词法上相同,也不会等于在单独执行该方法期间创建的第二个匿名函数。

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

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
        }

    };
}();

现在,由于 handler 始终严格等于其自身,removeEventListener 将成功删除处理程序。或者,第二个 addEventListener 将不执行任何操作(只保留当前处理程序)。

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

this.elt.addEventListener('click', handler.bind(this));

但这将无法完成您想要的,因为每次调用该方法时 handler.bind(this) 的值都不同,因此您将再次得到冗余的事件处理程序,或 removeEventListener 不起作用。

如果你真的想要对象的 this 在处理程序中,并且不知道如何从事件中检索它,你可以初始化 handler 的绑定(bind)版本在一些 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();

由于 this.handler 始终与其自身相同,因此它按预期工作。

使用EventListener

解决这个问题的一种更优雅的方法是传递给 addEventListener,而不是传递给函数,而是传递一个带有 EventListener 的对象。接口(interface),它是实现特别命名的 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);
    }
};

注意 this 被传递给 addEventListener。换句话说,我们正在传递对象本身,在它作为 EventListener 实例的化身中,由于它已经实现了 handleEventhandleEvent 是对象的完整方法,因此可以完全访问其所有方法和属性,并且因为 this 与自身相同,所以添加,再次添加,并根据需要删除行为。

我没有看到这种方法被广泛使用,但它可以使事件处理更加精简,特别是如果你在它周围添加一些糖,比如安排单独的方法来处理每种事件类型:

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);
    }
};

关于javascript - 更新或更改或删除/重置 Javascript 事件监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26007354/

相关文章:

javascript - 应用不同样式的文本

javascript - 在扩展的 div 中显示文本 W/CSS3 或 JavaScript/Jquery

jquery - Twitter Bootstrap - 导航栏切换不会在索引以外的页面上打开

javascript - jQuery UI 可排序 : Cannot add first element to linked element

javascript - React useState 不会在窗口事件中更新

html - 单击其他地方后,如何使按钮保持其焦点状态?

javascript - 计算父 Div 的定位

javascript - 使用数组索引在该数组的过滤版本中查找相应的索引

javascript - 将脚本应用于 Angular 2 上的输入

javascript - Highcharts.stockChart 不是函数