64 votes

L'élimination de modèle et de la vue des objets dans Backbone.js

Qui est le moyen le plus efficace de disposer modèle/vue instances lorsqu'il n'est pas nécessaire?

D'habitude, j'ai mis toute la logique du contrôleur/routeur. Il est celui qui décide, de ce point de vue devrait être créé, et ce que les modèles doivent être fournis. Habituellement, il ya quelques fonctions de gestionnaire, correspondant aux différentes actions de l'utilisateur ou de routes, où j'ai créer une nouvelle vue des instances à chaque fois qu'un gestionnaire soit exécutée. Bien sûr, ce qui devrait éliminer tout ce que j'ai déjà stockées dans l'instance de vue. Cependant, il existe certaines situations où certaines vues garder DOM gestionnaires d'événements eux-mêmes, et ils ne sont pas unbinded correctement, ce qui entraîne dans les cas être maintenu en vie. Je souhaite si il y avait une bonne façon de détruire la vue des cas, quand, par exemple, leur el DOM (la représentation) est détaché, ou jetés dans les DOM

77voto

Derick Bailey Points 37859

vous êtes sur le bon chemin. vous devez avoir un objet qui contrôle le cycle de vie de votre point de vue. je n'aime pas mettre ça dans ma vue. je voudrais créer un objet distinct pour cette.

la chose que vous devez faire, est de séparer les événements si nécessaire. pour ce faire, il est une bonne idée de créer un "proche" de la méthode sur l'ensemble de vos points de vue, et d'utiliser l'objet qui contrôle le cycle de vie de tout pour toujours appeler la méthode close.

par exemple:


  function AppController(){
    this.showView = function (view){
      if (this.currentView){
        this.currentView.close();
      }
      this.currentView = view;
      this.currentView.render();
      $("#someElement").html(this.currentView.el);
    }
  }

à ce stade, vous devez définir votre code afin d'avoir une seule instance de l'AppController, et vous devriez toujours faire appel à appController.showView(...) de votre routeur, ou tout autre code qui doit afficher une vue en #someElement partie de votre écran.

(j'ai un autre exemple très simple de la dorsale application qui utilise une "AppView" (l'épine dorsale de la vue qui exécute la partie principale de l'application), ici: http://jsfiddle.net/derickbailey/dHrXv/9/ )

l' close méthode n'existe pas sur les vues par défaut, vous devez créer un vous-même, pour chacun de vos points de vue. Il y a deux choses qui devraient toujours être dans le mode de fermeture: this.unbind() et this.remove(). en outre, si vous liez votre point de vue à n'importe quel modèle ou d'une collection d'événements, vous devez séparer dans la méthode close.

par exemple:


  MyView = Backbone.View.extend({
    initialize: function(){
      this.model.bind("change", this.modelChanged, this);
    },

    modelChanged: function(){
      // ... do stuff here
    },

    close: function(){
      this.remove();
      this.unbind();
      this.model.unbind("change", this.modelChanged);
    }
  });

cela permettra de bien nettoyer tous les événements du DOM (via this.remove()), tous les événements que la vue elle-même peut soulever (via this.unbind()) et le cas où le point de vue lié à partir du modèle (via this.model.unbind(...)).

13voto

Shaheen Ghiassy Points 1191

Un simpiler façon est d'ajouter des méthode de fermeture sur la colonne vertébrale.Afficher l'objet

Backbone.View.prototype.close = function () {
  this.$el.empty();
  this.unbind();
};

En utilisant le code ci-dessus, vous pouvez effectuer les opérations suivantes

var myView = new MyView();

myView.close();

facile comme bonjour.

6voto

Dano64 Points 154

J'ai toujours nuke les points de vue et parfois la réutilisation des modèles. Assurez vous que les points de vue sont désalloués peut être une douleur, si vous gardez les modèles autour de. Les modèles peuvent conserver une référence à la vue, si ils ne sont pas indépendant correctement.

Comme d'épine Dorsale ~0.9.9, modèles de liaison avec vue.listenTo() plutôt que de modèle.() facilite le nettoyage par inversion de contrôle (contrôle des liaisons par opposition à des modèles). Si la vue.listenTo() est utilisée pour lier, puis un appel à vue.stopListening() ou de la vue.remove() va supprimer toutes les liaisons. Similaire à l'appel du modèle.off(null, null, ce).

J'aime le nettoyage des vues en élargissant le point de vue d'une fonction de fermeture qui appelle les sous-vues de façon semi-automatique. Les sous-vues doivent être référencées par les propriétés de la mère ou ils doivent être ajoutés à un tableau à l'intérieur de la mère a appelé childViews[].

Ici est la fonction que j'utilise..

// fired by the router, signals the destruct event within top view and 
// recursively collapses all the sub-views that are stored as properties
Backbone.View.prototype.close = function () {

    // calls views closing event handler first, if implemented (optional)
    if (this.closing) {
        this.closing();  // this for custom cleanup purposes
    }

    // first loop through childViews[] if defined, in collection views
    //  populate an array property i.e. this.childViews[] = new ControlViews()
    if (this.childViews) {
        _.each(this.childViews, function (child) {
            child.close();
        });
    }

    // close all child views that are referenced by property, in model views
    //  add a property for reference i.e. this.toolbar = new ToolbarView();
    for (var prop in this) {
        if (this[prop] instanceof Backbone.View) {
            this[prop].close();
        }
    }

    this.unbind();
    this.remove();

    // available in Backbone 0.9.9 + when using view.listenTo, 
    //  removes model and collection bindings
    // this.stopListening(); // its automatically called by remove()

    // remove any model bindings to this view 
    //  (pre Backbone 0.9.9 or if using model.on to bind events)
    // if (this.model) {
    //  this.model.off(null, null, this);
    // }

    // remove and collection bindings to this view 
    //  (pre Backbone 0.9.9 or if using collection.on to bind events)
    // if (this.collection) {
    //  this.collection.off(null, null, this);
    // }
}

Ensuite, d'un point de vue est déclarée comme suit..

views.TeamView = Backbone.View.extend({

    initialize: function () {
        // instantiate this array to ensure sub-view destruction on close()
        this.childViews = [];  

        this.listenTo(this.collection, "add", this.add);
        this.listenTo(this.collection, "reset", this.reset);

        // storing sub-view as a property will ensure destruction on close()
        this.editView = new views.EditView({ model: this.model.edits });
        $('#edit', this.el).html(this.editView.render().el);
    },

    add: function (member) {
        var memberView = new views.MemberView({ model: member });
        this.childViews.push(memberView);    // add child to array

        var item = memberView.render().el;
        this.$el.append(item);
    },

    reset: function () {
        // manually purge child views upon reset
        _.each(this.childViews, function (child) {
            child.close();
        });

        this.childViews = [];
    },

    // render is called externally and should handle case where collection
    // was already populated, as is the case if it is recycled
    render: function () {
        this.$el.empty();

        _.each(this.collection.models, function (member) {
            this.add(member);
        }, this);
        return this;
    }

    // fired by a prototype extension
    closing: function () {
        // handle other unbinding needs, here
    }
});

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