更新或更改或删除/重置Javascript事件侦听器 [英] Update or Change or Remove/Reset Javascript event listener
问题描述
好的,所以我正在制作一个小的html5画布绘图库,我有一个小问题,这里是代码(小提琴):
var drawr = {
init:function(canvas_id,canvasWidth,canvasHeight){// height&宽度是可选的
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;
}
},
//魔术线绘制函数
ctx:function(a,b,x,y,dLineColor,dLineWidth){ // lineWidth& lineColor是可选的;默认值是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:function(){
//销毁事件处理程序
},
draw:function(lineColor,lineWidth){
//创建绘图函数的一些实用程序以使用
var localPen = {};
var drawing = false;
var canvasPos = {
x:this.canvas_id.offsetLeft,
y:this.canvas_id.offsetTop
}
//发起事件处理程序
this.canvas_id.addEventListener('mousedown',addDraw,false);
函数addDraw(e){
drawing = true;
console.log(绘图);
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();
第二个(或第三个等)为它覆盖前面的函数。我该怎么办呢?正如您在我的小提琴中所看到的,每个实例同时运行。
随意编辑,更新,删除,对我说错误代码等等。
调用 addEventListener
将覆盖前一个,或者调用 removeEventListener
将删除一个侦听器,只有当处理程序为该事件类型指定的函数严格等于。一个匿名函数,即使在词汇上是相同的,也不等于在单独执行该方法期间创建的第二个匿名函数。
这里有一个想法:将你的处理程序定义为闭包中的单独函数,如下所示:
obj = function(){
function handler(){/ *处理点击; this是元素* /}
return {
draw:function(){
this.elt.addEventListener('click',handler);
//绘制一堆东西
},
undraw:function(){
this.elt.removeEventListener('click',handler);
//解开一堆东西
}
};
}();
现在,由于处理程序
始终严格相等本身, removeEventListener
将成功移除处理程序。或者,第二个 addEventListener
将不会执行任何操作(只保留当前的处理程序)。
然而, code> handler 无法访问该对象的此
;它将被事件的目标元素调用为 this
。为了将对象的此
添加到事件处理程序中,您可能会尝试
this.elt.addEventListener('click',handler.bind(this));
但是这将无法实现您想要的,因为处理程序的值每次调用方法时,.bind(this)
都不同,所以你将再次使用冗余事件处理程序,或 removeEventListener
s如果你真的想在对象的这个
处理程序中,并不能找出如何从事件中检索它,你可以在一些 init
函数中初始化一个处理程序
的绑定版本:
obj = {
处理程序:function(event){/ *处理单击; this是对象* /},
draw:function(){
this.elt.addEventListener('click',this.handler);
//绘制一堆东西
},
undraw:function(){
this.elt.removeEventListener('click',this.handler);
//取出一堆东西
},
init:function(){
this.handler = this.handler.bind(this);
返回此;
}
} .init();
由于 this.handler
总是相同的使用 EventListener
使用 p>解决这个问题的一个更好的方法是传递给
addEventListener
,而不是一个函数,一个带有 EventListener 接口,它是实现特殊命名的 handleEvent
方法,它可以是'this'对象本身,所以你可以这样做:
obj = {
handleEvent:function(event){
//this是对象
if(event.type ==='click'){
// do stuff
}
},
draw:function(){
this.elt.addEventListener('click',this);
},
undraw:function(){
this.elt.removeEventListener('click',this);
}
};
注意 我没有看到这个方法被使用得非常多,但它可以使事件处理更加流畅,特别是如果你在它周围添加一些糖,比如安排个别方法来处理每一个事件类型:这个
传递给的addEventListener
。换句话说,我们通过实现 handleEvent $ c>来传递对象本身,作为
EventListener
的一个实例$ C>。 handleEvent
是一个完整的对象方法,因此可以完全访问它的所有方法和属性,并且因为 this
与自身相同,添加,添加和删除行为可以根据需要使用。
$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ [event.type](事件); //调度到事件名称为
}的方法,
点击:function(event){
//句柄点击; this是obj
},
draw:function(){
this.elt.addEventListener('click',this);
},
undraw:function(){
this.elt.removeEventListener('click',this);
}
};
Ok, so I'm working on a small html5 canvas drawing library and I'm having a slight problem, here's the code (fiddle below):
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);
What I'm trying to accomplish here is this: when I call drawr.draw();
a second (or third, etc) for it to override the previous function. How should I go about this? As you can see in my fiddle each instance simultaneously runs.
Feel free to edit, update, delete, yell at me for bad code, etc.
A call to addEventListener
will override the previous one, or a call to removeEventListener
will remove a listener, only when the handler functions specified for that event type are strictly equal. A anonymous function, even if lexically identical, will not be equal to a second anonymous function created during a separate execution of the method.
Here's one idea: define your handler as a separate function in a closure, as follows:
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
}
};
}();
Now, since handler
is always strictly equal to itself, the removeEventListener
will successfully remove the handler. Or, a second addEventListener
will not do anything (just leave the current handler in place).
However, handler
has no access to the this
of the object; it will be called with the event's target element as its this
. In order to get the object's this
into the event handler, you may be tempted to try
this.elt.addEventListener('click', handler.bind(this));
but this will fail to accomplish what you want, because the value of handler.bind(this)
is different each time the method is invoked, so you will again end up with redundant event handlers, or removeEventListener
s which do not work.
If you really want the object's this
in the handler, and can't figure out how to retrieve it from the event, you could initialize a bound version of handler
in some init
function:
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();
Since this.handler
is always identical to itself, this works as expected.
Using EventListener
A somewhat more elegant way to solve this problem is to pass to addEventListener
, instead of a function, an object with the EventListener interface, which is any object that implements the specially-named handleEvent
method, which could be the 'this' object itself, so you can do:
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);
}
};
Note the this
being passed to addEventListener
. In other words, we are passing the object itself, in its incarnation as an instance of EventListener
, by virtue of its having implemented handleEvent
. handleEvent
is a full-fledged method of the object and as such has full access to all its methods and properties, and because this
is identical to itself, the adding, adding again, and removing behavior works as you want.
I don't see this approach used very much, but it can make event handling more streamlined, especially if you add some sugar around it, such as arranging for individual methods to handle each event type:
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事件侦听器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!