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

Sub Class a Backbone.View. Подкласс и сохранение событий.

У меня есть общий подкласс Backbone.View, который имеет прослушиватель событий close.

var GenericView = Backbone.View.extend({

    events : {
        "click .close" : "close"
    },

    close : function () {
        console.log("closing view");
    }

});

Я хочу подклассифицировать этот общий класс и добавить некоторые новые события. Однако ниже будет перезаписываться объект событий super classes (выше). Например.

var ImplementedView = new GenericView({

    // setting this will stop 'close' in Super Class from triggering
    events : {
        "click .submit" : "submit"
    }

}); 

Как мне создать подкласс, в данном случае ImplementedView и сохранить события?

Я нашел один способ достичь этого, расширив объект события, когда построен дочерний класс. Однако мне нужно перезапустить this.delegateEvents(), который, как я предполагаю, не очень хорош. Может ли кто-нибудь прокомментировать это?

var ImplementedView = new GenericView({

    initialize : function (options) {

        _.extend(this.events, {
            "click .submit" : "submit"
        });

        // re-attach events
        this.delegateEvents();
    }

});
4b9b3361

Ответ 1

@Nupul в точности соответствует: вы не подклассифицируете свой GenericView.

На самом деле подклассификация здесь не является правильным словом, поскольку JavaScript не выполняет классического наследования.

Итак, давайте сначала попытаемся понять, что происходит здесь:

var GenericView = Backbone.View.extend( propertiesObj, classPropertiesObj )

Backbone.View - это функция-конструктор, которая при вызове с ключевым словом new создает для вас новый объект.

Поскольку это JS, все функции являются действительно объектами функции, поэтому Backbone.View.extend - это просто функция, зависающая от Backbone.View, которая выполняет несколько действий:

  • Он устанавливает цепочку прототипов, поэтому вы можете обращаться к свойствам и функциям вызова, определенным в классе "base"
  • Он создает и возвращает новую конструкторскую функцию, которую вы можете вызвать (которая здесь была бы GenericView) для создания объектов вашего класса наследования
  • Он копирует себя как функцию, зависающую от возвращаемой функции-конструктора, чтобы вы могли наследовать.

Таким образом, правильный способ настройки цепи protoype вы хотите:

var ImplementedView = GenericView.extend({
  // implementation goes here
});

и NOT:

var ImplementedView = new GenericView({//stuff});

потому что это просто создает новый экземпляр GenericView.

Теперь у вас все еще есть проблема, потому что когда вы делаете что-то вроде:

var impl_view = new ImplementedView;

impl_view.events; // This isn't merged with the events you created
                  // for the GenericView

В этот момент есть разные способы получить желаемый результат, вот тот, который использует delegateEvents вроде того, как вы это делали. Кстати, использование этого неплохо.

var GenericView = Backbone.View.extend({

  genericEvents: { 'click .close': 'close' },

  close: function() { console.log('closing view...'); }

});

var ImplView = GenericView.extend({

  events: { 'click .submit': 'submit' },

  initialize: function(options) {
    // done like this so that genericEvents don't overwrite any events
    // we've defined here (in case they share the same key)
    this.events = _.extend({}, this.genericEvents, this.events);
    this.delegateEvents()
  }
});

Ответ 2

Другой вариант - иметь BaseView, который переопределяет реализацию Extend. Например:

var BaseView = Backbone.View.extend({
        //base view functionality if needed
    });
BaseView.extend = function(child){
    var view = Backbone.View.extend.apply(this, arguments);
    view.prototype.events = _.extend({}, this.prototype.events, child.events);
    return view;
};

Это автоматически расширит все ваши события для всего, что наследуется от BaseView.

Ответ 3

Мне нравится решение г-на Бритва, но для чего-то менее навязчивого:

var ChildView = ParentView.extend({
    events : _.extend({
        "change input": "handleInputChange"
    }, ParentView.prototype.events)
});

Изменить. Да, вы должны сделать это в каждом дочернем классе, но это полезно, когда нужны только несколько детей или когда вы не контролируете родительский "класс".

Ответ 4

Вот решение, которое хорошо сработало для меня. Вы можете использовать объект events как в родительском, так и в подклассе, без расширения в нем каждого подкласса. Просто добавьте его один раз в родительский класс:

APP.Views.GenericWizard = Backbone.View.extend({
  events: {
    'click .btn-prev'   : function(){}
  },
  initialize: function() {
    _(this.events).extend(APP.Views.GenericWizard.prototype.events);
  }
});

APP.Views.RegisterWizard = APP.Views.GenericWizard.extend({
  events: {
    'blur #username' : function(){}
  },
});

var registerWizard = new APP.Views.RegisterWizard();
console.log(registerWizard.events);
// Object {blur #username: function, click .btn-prev: function}