Mettre à jour ou modifier ou Supprimer / Réinitialiser l'auditeur d'événement Javascript

Ok, alors je travaille sur une petite bibliothèque de dessins en toile html5 et j'ai un petit problème, voici le code (violon ci-dessous):

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

Ce que j'essaie d'accomplir ici est la suivante: quand j'appelle drawr.draw(); Une seconde (ou une troisième, etc.) afin de remplacer la fonction précédente. Comment puis-je aborder cela? Comme vous pouvez le voir dans mon viol, chaque instance s'exécute simultanément.

N'hésitez pas à modifier, mettre à jour, supprimer, me crier pour mauvais code, etc.

Un appel à addEventListener remplacera le précédent, ou un appel à removeEventListener supprimera un auditeur, uniquement lorsque les fonctions du gestionnaire spécifiées pour ce type d'événement sont strictement égales . Une fonction anonyme, même si elle est lyniquement identique, ne sera pas égale à une seconde fonction anonyme créée lors d'une exécution distincte de la méthode.

Voici une idée: définissez votre gestionnaire comme une fonction distincte dans une fermeture, comme suit:

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

Maintenant, puisque handler est toujours strictement égal à lui-même, le removeEventListener supprimera avec succès le gestionnaire. Ou, un second addEventListener ne fera rien (il suffit de laisser le gestionnaire actuel en place).

Cependant, le handler n'a pas accès à this de l'objet; Il sera appelé avec l'élément cible de l'événement en tant que this . Afin d'obtenir l'objet dans le gestionnaire d'événements, vous pourriez être tenté d'essayer

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

Mais cela n'arrivera pas à accomplir ce que vous voulez, car la valeur de handler.bind(this) est différente chaque fois que la méthode est appelée, de sorte que vous allez de nouveau se retrouver avec des gestionnaires d'événements redondants ou removeEventListener s qui ne fonctionnent pas.

Si vous voulez vraiment l'objet dans le gestionnaire, et que vous ne pouvez pas comprendre comment le récupérer à partir de l'événement, vous pouvez initialiser une version liée du handler dans une fonction d' 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(); 

Étant donné que this.handler est toujours identique à lui-même, cela fonctionne comme prévu.

Utilisation de EventListener

Une façon un peu plus élégante de résoudre ce problème est de passer à addEventListener , au lieu d'une fonction, un objet avec l'interface EventListener , qui est un objet qui implémente la méthode handleEvent spécialement nommée, qui pourrait être l'objet 'this' lui-même, Afin que vous puissiez:

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

Notez this étant passé à addEventListener . En d'autres termes, nous passons l'objet lui-même, dans son incarnation en tant EventListener , en raison de sa mise en œuvre de handleEvent . handleEvent est une méthode à part entière de l'objet et, en tant que tel, a un accès complet à toutes ses méthodes et propriétés, et parce que this est identique à lui-même, l'ajout, l'ajout à nouveau et la suppression du comportement fonctionnent comme vous le souhaitez.

Je ne vois pas très bien cette approche, mais cela peut rendre la gestion des événements simplifiée, surtout si vous ajoutez de la sucre autour de celle-ci, comme l'organisation de méthodes individuelles pour gérer chaque type d'événement:

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