Подтвердить что ты не робот

Как я могу прикрепить 2 обработчика к одному и тому же событию?

Я могу привязывать обработчики к Backbone Views следующим образом:

var TodoView = Backbone.View.extend({
    events: {
        "xxx": "eventHandler1"
        "yyy": "eventHandler2"
    }
});

Но что, если я хочу добавить более одного обработчика к тому же событию?

var TodoView = Backbone.View.extend({
    events: {
        "xxx": "eventHandler1"
        "yyy": "eventHandler2"
        "xxx": "eventHandler3" // this isn't valid ... at least in CoffeeScript
    }
});

Я мог бы создать собственный обработчик, например

function compositeXXX() { eventHandler1(); eventHandler2 }

Но это не кажется идеальным...

4b9b3361

Ответ 1

Это:

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'`

не будет работать, так как Backbone не поймет, что он должен разделить значение на пробелы; аналогичным образом:

'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() { ... }

то он используется как-is, в противном случае он преобразуется в свойство 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' ]

Если вы не хотите исправлять свою магистраль или пересылать такой патч для поддерживающих Backbone, вы можете пойти с оригинальной идеей "ручной диспетчеризации":

'event selector': 'dispatcher'
//...
dispatcher: function(ev) {
    this.handler1(ev);
    this.handler2(ev);
}

Ответ 2

Я решил эту проблему, используя пространства имен событий jQuery

var TodoView = Backbone.View.extend({
    events: {
        "xxx.handler1": "eventHandler1",
        "yyy": "eventHandler2",
        "xxx.handler3": "eventHandler3"
    }
});

Это не то, для чего первоначально предназначалось пространство имен, но если они не сталкиваются с другими пространствами имен, это не должно вызывать проблемы.

Основная проблема заключается только в том, что вы можете иметь только одно значение для каждого ключа в объекте, и это делает ключи уникальными.