Наследование backbone.js

У меня есть вид под названием Pannel, который является фоном с кнопкой закрытия. Я хочу расширить этот вид до одного, называемого PannelAdvanced. Как мне сделать это с помощью backbone.js?

В настоящее время все примеры имеют Backbone.View.Extend, но они просто расширяются Backbone.View; Я хочу расширить PannelView.

Ответ 1

Самый простой способ наследовать представление - сделать то, что другие люди уже предложили в комментариях:

var Pannel = Backbone.View.extend({
});

var PannelAdvanced = Pannel.extend({
});

Но, как вы отметили в своих комментариях, если у вас есть метод инициализации в Pannel, он не будет вызываться, если вы также имеете метод инициализации в PannelAdvanced, поэтому вам нужно явно вызвать метод инициализации Pannel:

var Pannel = Backbone.View.extend({
   initialize: function(options){
      console.log('Pannel initialized');
      this.foo = 'bar';
   }
});

var PannelAdvanced = Pannel.extend({
   initialize: function(options){
      Pannel.prototype.initialize.apply(this, [options])
      console.log('PannelAdvanced initialized');
      console.log(this.foo); // Log: bar
   }
});

Это немного уродливо, потому что, если у вас много просмотров, которые наследуются от Pannel, вам придется не забудьте вызвать Pannel для инициализации из всех них. Хуже того, если Pannel теперь не имеет метода инициализации, но вы хотите добавить его в будущем, тогда вам нужно будет перейти ко всем унаследованным классам в будущем и убедиться, что они вызывают инициализацию Pannel. Итак, вот альтернативный способ определения Pannel, чтобы ваши унаследованные представления не нуждались в вызове метода инициализации Pannel:

var Pannel = function (options) {

    // put all of Panel initialization code here
    console.log('Pannel initialized');
    this.foo = 'bar';

    Backbone.View.apply(this, [options]);
};

_.extend(Pannel.prototype, Backbone.View.prototype, {

    // put all of Panel methods here. For example:
    sayHi: function () {
        console.log('hello from Pannel');
    }
});

Pannel.extend = Backbone.View.extend;


// other classes inherit from Panel like this:
var PannelAdvanced = Pannel.extend({

    initialize: function (options) {
        console.log('PannelAdvanced initialized');
        console.log(this.foo);
    }
});

var pannelAdvanced = new PannelAdvanced(); //Log: Pannel initialized, PannelAdvanced initialized, bar
pannelAdvanced.sayHi(); // Log: hello from Pannel

Ответ 2

Это одна из причин, по которой мне очень нравится использовать Coffeescript. Такие вещи, как наследование, гораздо приятнее. Чтобы скомпоновать @JohnnyO правильный ответ, я могу сказать то же самое в Coffeescript:

class Panel extends Backbone.View
    initialize: ->
        console.log 'Panel initialized'
        @foo = 'bar'

class PanelAdvanced extends Panel
    initialize: ->
        super
        console.log 'PanelAdvanced initialized'
        console.log @foo

Ответ 3

Чтобы немного контрейлерировать:

Мне понравился подход @JohnnyO, но я хотел подтвердить, что результирующее представление все еще способно делать все, что ему нужно. Учитывая его подход, я не подозревал, что будут какие-то проблемы, но я хотел бы быть более уверенным.

Итак, я потратил минуту и ​​адаптировал Backbone.js набор тестов для поиска для метода множественного наследования @JohnnyO.

Результаты можно выполнить с http://jsfiddle.net/dimadima/nPWuG/. Все тесты проходят.

Мои базовые и расширенные виды:

var RegularView = function (options) {
  // All of this code is common to both a `RegularView` and `SuperView`
  // being constructed.
  this.color = options && (options.color || 'Green');

  // If execution arrives here from the construction of
  // a `SuperView`, `Backbone.View` will call `initialize`
  // that belongs to `SuperView`. This happens because here
  // `this` is `SuperView`, and `Backbone.View`, applied with
  // the current `this` calls `this.initialize.apply(this, arguments)`
  Backbone.View.apply(this, arguments)
};

RegularView.extend = Backbone.View.extend;

_.extend(RegularView.prototype, Backbone.View.prototype, {
  // Called if a `RegularView` is constructed`,
  // Not called if a `SuperView` is constructed.
  initialize: function () {
    console.log('RegularView initialized.');
  },

  say_hi: function() {
    console.log('Regular hi!');
  }

});

var SuperView = RegularView.extend({
  // Called if a `SuperView` is constructed`,
  // Not called if a `RegularView` is constructed.
  initialize: function(options) {
    console.log('SuperView initialized.')
  },

  say_hi: function() {
    console.log('Super hi!');
  }
})

В тестовом наборе я схватил последние просмотры тестов из GitHub и заменил вхождения Backbone.View на RegularView. Затем тесты используют RegularView и результаты RegularView.extend(), чтобы убедиться, что оба делают то, что они должны.