41 votes

Héritage des vues dans Backbone.js

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

Pour l'instant, tous les exemples ont Backbone.View.Extend mais ceux-là ne font que s'étendre Backbone.View ; je veux étendre mon PannelView .

0 votes

Cela fonctionne exactement de la même manière - Panel.extend({ ... })

0 votes

J'ai mon Panel = Backbone.View.extend() puis j'ai advancedPanel = Panel.extend() mais lorsque je fais un journal de la console pour une variable dans la méthode initialize du Panel à l'intérieur d'advancedPanel, il apparaît comme indéfini.

0 votes

Puis-je simplement appeler Panel.extend() sans instancier Panel au préalable.

100voto

Johnny Oshika Points 15580

Le moyen le 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 d'initialisation dans Pannel, elle ne sera pas appelée si vous avez également une méthode d'initialisation dans PannelAdvanced, vous devez donc appeler la méthode d'initialisation de Pannel explicitement :

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 laid car si vous avez beaucoup de Views qui héritent de Pannel, vous devrez vous souvenir d'appeler l'initialize de Pannel à partir de chacun d'eux. Pire encore, si Pannel n'a pas de méthode initialize maintenant mais que vous décidez de l'ajouter à l'avenir, vous devrez alors vous rendre dans toutes les classes héritées à l'avenir et vous assurer qu'elles appellent la méthode initialize de Pannel. Voici donc une autre façon de définir Pannel pour que les vues héritées n'aient pas besoin d'appeler la méthode initialize 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

1 votes

Ce modèle ne fonctionne pas lorsque des événements sont déclarés à la fois dans le parent et dans l'enfant, car la clé d'événements du parent dans le dict est remplacée par celle de l'enfant lorsque l'on appelle var PannelAdvanced = Pannel.extend({events:{...}}) . Vous pouvez déclarer une clé parentsEvents dans le parent, et appeler alors this.delgateEvents(this.parentEvents) dans le constructeur parent mais ensuite, en raison de cette ligne dans backbone, ils seront à nouveau abandonnés à cause de la vue enfant.

2 votes

En fait, vous pouvez le faire. Déclarez les événements enfants dans une clé childEvents ou autre, puis dans le parent, déclarez une clé events fonction avec : return _.extend({"click .parentClass": "parentFunction"}, this.childEvents)

0 votes

Utilisation de _super n'est pas le meilleur choix. github.com/jashkenas/backbone/pull/787#issuecomment-14327908

29voto

Brian Genisio Points 30777

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

6 votes

J'ai traduit ça en javascript juste pour voir si j'arrive à l'écrire : jsfiddle.net/7qssz super devient Panel.prototype.initialize.apply(this, arguments);

0 votes

Je n'ai pas réussi à le faire fonctionner en passant des arguments. Ils n'apparaissent pas dans this.options .

0 votes

@Maletor : Quelle version de Backbone utilisez-vous ? Il a été ajouté vers la version 0.9.9 ou quelque chose comme ça.

8voto

dimadima Points 2803

Pour revenir un peu en arrière :

J'ai aimé l'approche de @JohnnyO mais je voulais confirmer que la vue résultante était toujours capable de faire tout ce qu'elle est 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 sûr.

Donc, j'ai pris une minute et j'ai adapté le Suite de tests Backbone.js Views à la technique de l'héritage multiple que propose @JohnnyO.

Vous pouvez consulter les résultats à l'adresse suivante http://jsfiddle.net/dimadima/nPWuG/ . Tous les tests sont réussis.

Mes vues de base et étendue :

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 récupéré le les derniers tests de vues depuis GitHub et remplacé les occurrences de Backbone.View con 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X