【问题标题】:Update or Change or Remove/Reset Javascript event listener更新或更改或删除/重置 Javascript 事件侦听器
【发布时间】:2014-09-24 01:59:06
【问题描述】:

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

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 中看到的那样,每个实例同时运行。

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

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    仅当为该事件类型指定的处理函数严格相等时,对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
            }
    
        };
    }();
    

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

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

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

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

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

    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接口的对象,它是任何实现了特别命名的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);
        }
    };
    

    【讨论】:

    • 好的,我要试一试。我会告诉你进展如何!
    • 我想要的方式是最合乎逻辑的吗?使用事件处理程序等?我应该考虑不同的方法吗?
    • 不太清楚你在问什么——如果你想处理事件,你需要事件处理程序。
    • 我喜欢您标题为 Event Listener 的第一个解决方案,认为我的方法就是我想要达到的目标。我还没有机会尝试。如果一切顺利,我会回来给你绿支票。同时为您的所有时间和精力 +1!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多