web-dev-qa-db-fra.com

Héritage de vue Backbone.js

J'ai une vue appelée Pannel qui n'est qu'un arrière-plan avec un bouton de fermeture. Je veux étendre cette vue à une appelée PannelAdvanced. Comment pourrais-je faire cela avec backbone.js?

À l'heure actuelle, tous les exemples ont Backbone.View.Extend mais ceux-ci s'étendent simplement Backbone.View; Je souhaite étendre mon PannelView.

40
Chapsterj

La façon la plus simple d'hériter d'une vue est de faire ce que d'autres personnes ont déjà suggéré dans les commentaires:

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

var PannelAdvanced = Pannel.extend({
});

Mais comme vous l'avez noté dans vos commentaires, si vous avez une méthode initialize dans Pannel, elle ne sera pas appelée si vous avez également une méthode initialize dans PannelAdvanced, vous devez donc appeler explicitement la méthode initialize de 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
   }
});

C'est un peu moche parce que si vous avez beaucoup de vues qui héritent de Pannel, alors vous devrez vous rappeler d'appeler l'initialisation de Pannel à partir de toutes. Pire encore, si Pannel n'a pas de méthode d'initialisation maintenant mais que vous choisissez de l'ajouter à l'avenir, vous devrez alors accéder à toutes les classes héritées à l'avenir et vous assurer qu'elles appellent initialisation de Pannel. Voici donc une autre façon de définir Pannel afin que vos vues héritées n'aient pas besoin d'appeler la méthode d'initialisation de Pannel:

var Pannel = function (options) {

    // put all of Panel's 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's 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
100
Johnny Oshika

C'est l'une des raisons pour lesquelles j'aime tellement utiliser Coffeescript. Des choses comme l'héritage sont tellement plus belles. Pour ferroutage @ réponse correcte de JohnnyO, je peux dire la même chose dans 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
29
Brian Genisio

Pour continuer un peu:

J'ai aimé l'approche de @ JohnnyO mais je voulais confirmer qu'une vue résultante était toujours capable de faire tout ce qu'elle était censée faire. Compte tenu de son approche, je ne pensais pas qu'il y aurait des problèmes, mais je voulais être un peu plus certain.

J'ai donc pris une minute et adapté la Suite de tests Backbone.js Views à la technique d'héritage multiple proposée par @JohnnyO.

Vous pouvez exécuter les résultats sur http://jsfiddle.net/dimadima/nPWuG/ . Tous les tests réussissent.

Mes vues de base et étendues:

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!');
  }
})

Pour la suite de tests, j'ai saisi les derniers tests de vues de GitHub et remplacé les occurrences de Backbone.View Par RegularView. Les tests utilisent ensuite RegularView et les résultats de RegularView.extend() pour s'assurer que les deux font ce qu'ils sont censés faire.

8
Dmitry Minkovsky