Как подключить 2 обработчика к одному событию?
Я могу прикрепить обработчики к основным представлениям, таким как:
var TodoView = Backbone.View.extend({
events: {
"xxx": "eventHandler1"
"yyy": "eventHandler2"
}
});
но что, если я хочу прикрепить более 1 обработчика к одному и тому же событию?
var TodoView = Backbone.View.extend({
events: {
"xxx": "eventHandler1"
"yyy": "eventHandler2"
"xxx": "eventHandler3" // this isn't valid ... at least in CoffeeScript
}
});
я мог бы создать пользовательский обработчик, такой как
function compositeXXX() { eventHandler1(); eventHandler2 }
но это не кажется идеальным ...
2 ответов
это:
events: {
"xxx": "eventHandler1",
"yyy": "eventHandler2",
"xxx": "eventHandler3"
}
не будет работать, потому что events
является объектным литералом,и вы можете иметь не более одной пары (ключ, значение) в объекте. Это, вероятно, то же самое, что сказать:
events: {
"xxx": "eventHandler3",
"yyy": "eventHandler2"
}
Это CoffeeScript:
events:
"xxx": "eventHandler1"
"yyy": "eventHandler2"
"xxx": "eventHandler3"
функционально идентична версии JavaScript и не будет работать по той же причине.
идея Энди Рэя об использовании
'event selector': 'callback1 callback2'`
не будет работать, так как позвоночник не поймет, что он должен разделить значение на пробелы; аналогично, это:
'event selector': [ 'callback1', 'callback2' ]
не будет работать, потому что Backbone не знает, что делать с массивом в этом контексте.
представления связывают свои события через delegateEvents
и выглядит так:
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...
}
}
так method
начинается как значение 'event selector'
. Если это функция от чего-то вроде:
'event selector': function() { ... }
затем он используется как есть, иначе он преобразуется в свойство this
:
method = this[events[key]]; // i.e. method = this[method]
если кто смелый, можно отрегулировать delegateEvents
чтобы понять строку с разделителями массива или пробелов:
// 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...
}
довольно простой патч, как это позволит вам использовать пробелы запятыми список обработчиков:
'event selector': 'callback1 callback2'
или массив обработчиков:
'event selector': [ 'callback1', 'callback2' ]
или даже смешанный массив имен методов и функций:
'event selector': [ 'callback_name1', function() { ... }, 'callback_name2' ]
если вы не хотите латать позвоночник или переслать такой патч затем вы можете пойти с оригинальной идеей "ручной диспетчеризации":
'event selector': 'dispatcher'
//...
dispatcher: function(ev) {
this.handler1(ev);
this.handler2(ev);
}
Я решил эту проблему с помощью пространства имен событий jQuery
var TodoView = Backbone.View.extend({
events: {
"xxx.handler1": "eventHandler1",
"yyy": "eventHandler2",
"xxx.handler3": "eventHandler3"
}
});
это не то, для чего изначально предназначались пространства имен событий, но пока они не конфликтуют с другими пространствами имен, это не должно вызывать проблем.
основная проблема заключается в том, что вы можете иметь только одно значение на ключ в объекте, и это делает ключи уникальными.