javascript - sitios - ¿Cómo puedo adjuntar 2 manejadores al mismo evento?
manejo de eventos en sitios web (2)
Puedo adjuntar controladores a vistas principales como:
var TodoView = Backbone.View.extend({
events: {
"xxx": "eventHandler1"
"yyy": "eventHandler2"
}
});
Pero, ¿qué ocurre si quiero adjuntar más de 1 controlador al mismo evento?
var TodoView = Backbone.View.extend({
events: {
"xxx": "eventHandler1"
"yyy": "eventHandler2"
"xxx": "eventHandler3" // this isn''t valid ... at least in CoffeeScript
}
});
Podría crear un controlador personalizado como
function compositeXXX() { eventHandler1(); eventHandler2 }
Pero esto no parece ideal ...
Esta:
events: {
"xxx": "eventHandler1",
"yyy": "eventHandler2",
"xxx": "eventHandler3"
}
no funcionará porque los events
son un objeto literal y puede tener como máximo un par (clave, valor) en un objeto. Eso probablemente sería lo mismo que decir:
events: {
"xxx": "eventHandler3",
"yyy": "eventHandler2"
}
Este CoffeeScript:
events:
"xxx": "eventHandler1"
"yyy": "eventHandler2"
"xxx": "eventHandler3"
es funcionalmente idéntico a la versión de JavaScript y no funcionará por la misma razón.
La idea de Andy Ray de usar
''event selector'': ''callback1 callback2''`
tampoco funcionará, ya que Backbone no comprenderá que debe dividir el valor en espacios en blanco; Del mismo modo, esto:
''event selector'': [ ''callback1'', ''callback2'' ]
no funcionará porque Backbone no sabe qué hacer con una matriz en este contexto.
Las vistas vinculan sus eventos a través de delegateEvents
y se ve así:
delegateEvents: function(events) {
// Some preamble that doesn''t concern us here...
for (var key in events) {
var method = events[key];
if (!_.isFunction(method)) method = this[events[key]];
if (!method) throw new Error(''Method "'' + events[key] + ''" does not exist'');
// And some binding details that are of no concern either...
}
}
Entonces el method
comienza como el valor para ''event selector''
. Si es una función de algo como:
''event selector'': function() { ... }
luego se usa tal cual, de lo contrario se convierte en una propiedad de this
:
method = this[events[key]]; // i.e. method = this[method]
Si uno fuera negrita, se podría ajustar delegateEvents
para comprender una cadena delimitada por un conjunto o por espacios en blanco:
// Untested code.
var methods = [ ];
if (_.isArray(method))
methods = method;
else if (_.isFunction(method))
methods = [ method ];
else
methods = method.split(//s+/);
for (var i = 0; i < methods.length; ++i) {
method = methods[i];
if (!_.isFunction(method))
method = this[method];
// And the rest of the binding stuff as it is now with a possible adjustment
// to the "method does not exist" exception message...
}
Un parche bastante simple como ese le permitiría usar una lista de manipuladores delimitada por espacios en blanco:
''event selector'': ''callback1 callback2''
o una variedad de controladores:
''event selector'': [ ''callback1'', ''callback2'' ]
o incluso una combinación mixta de nombres y funciones de métodos:
''event selector'': [ ''callback_name1'', function() { ... }, ''callback_name2'' ]
Si no quiere parchear su Backbone o reenviar dicho parche a los mantenedores de Backbone, entonces podría ir con su idea original de "envío manual":
''event selector'': ''dispatcher''
//...
dispatcher: function(ev) {
this.handler1(ev);
this.handler2(ev);
}
Resolví este problema usando los espacios de nombres de eventos de jQuery
var TodoView = Backbone.View.extend({
events: {
"xxx.handler1": "eventHandler1",
"yyy": "eventHandler2",
"xxx.handler3": "eventHandler3"
}
});
Esto no es para lo que originalmente se diseñaron los espacios de nombres de eventos, pero siempre y cuando no entren en conflicto con otros espacios de nombres, no debería causar un problema.
El problema principal es que solo puede tener un valor por clave en un objeto y esto hace que las claves sean únicas.