使用Backbone.js中的路由在一个页面应用中管理多个视图实例

时间:2012-06-04 04:57:07

标签: javascript backbone.js

我正在使用Backbone.js开发单页应用。我遇到的一个问题是,由于一个人没有重新加载页面,当一个人创建一个View实例时,我认为,View对象将在应用程序的生命周期内保留在内存中。这对我来说似乎不是很有效,因为如果调用另一个路由,则可能不再需要特定视图。但是,如果返回到原始路线,则稍后可能需要“显示”特定视图。所以问题是,如何最好地管理Backbone中关于路由的视图?

在我的应用程序中,许多视图负责显示特定的“页面”,因此共享相同的DOM元素。当调用其中一个“页面”视图时,它将替换先前视图中先前放置的DOM元素中的内容。因此不再需要先前的视图。

我是否需要以某种方式手动销毁前一个View(或者这是由Router对象以某种方式处理)?或者,一旦初始化后留下观点会更好吗?

以下示例代码显示了如何在应用程序的路由器中创建视图实例。

/** 
 * View - List of contacts 
 */    
var ListContactsView = Backbone.View.extend({
  el: '#content',
  template: _.template($('#list-contacts-tpl').html()),
  initialize: function() {
    _.bindAll(this, 'render');
    this.collection = new Contacts();
    this.collection.bind('reset', this.render);
    this.collection.fetch();
  },
  render: function() {
    this.$el.hide();
    this.$el.html(this.template({ contacts: this.collection }));
    this.$el.fadeIn(500);
  }
});

/** 
 * View - Display single contact 
 */
var DisplayContactView = Backbone.View.extend({
  el: '#content',
  events: {
    'click #delete-contact-button': 'deleteContact'
  },
  template: _.template($('#display-contact-tpl').html()),
  initialize: function() {
    _.bindAll(this, 'deleteContact', 'render');
    // Create reference to event aggregator object.
    if (typeof this.options.id === 'undefined') {
      throw new Error('View DisplayContactView initialized without _id parameter.');
    }
    this.model = new Contact({ _id: this.options.id });
    // Add parse method since parsing is not done by collection in this 
    // instance, as this model is not called in the scope of collection 
    // Contacts.
    this.model.parse = function(response) {
      return response.data;
    };
    this.model.bind('change', this.render);
    this.model.fetch();
  },
  deleteContact: function(id) {
    // Trigger deleteContact event.
    this.eventAggregator.trigger('deleteContact', id);
  },
  render: function() {
    this.$el.html(this.template({ contact: this.model.attributes }));
  }
});

/**
 * Page routes
 */
var $content = $('#content');
var ClientSideRouter = Backbone.Router.extend({
  routes: {
    'browse': 'browse',
    'browse/view/:id': 'browseViewContact',
    'orgs': 'orgs',
    'orgs/:orgName': 'orgs',
    'orgs/:orgName/:id': 'orgs',
    'contact/add': 'addContact',
    'contact/view/:id': 'viewContact',
    'contact/delete/:id': 'confirmDelete',
    '*path': 'defaultPage'
  },
  addContact: function() {
    // Display contact edit form.
    var editContactFormView = new EditContactFormView();
    // Display email field in edit form.
  },
  browse: function() {
    var listContactsView = new ListContactsView();
  },
  browseViewContact: function(id) {
    var displayContactView = new DisplayContactView({ id: id });
  },
  defaultPage: function(path) {
    $content.html('Default');
  },
  home: function() {
    $content.html('Home');
  },
  viewContact: function(id) {
    $.ajax({
      url: '/contact/view/' + id,
      dataType: 'html',
      success: function(data) {
        $content.html(data);
      }
    });
  }
});

var clientSideRouter = new ClientSideRouter();
Backbone.history.start();

2 个答案:

答案 0 :(得分:2)

  • 路线不会破坏视图

路由为您提供了与网址更改进行交互的便捷方式。方便我指的是url语义和当前页面的上下文。例如,url #/!/create/将调用应显示表单以创建模型的方法。这里的上下文是创建模型的视图。

  • 视图应由开发人员管理

在Backbone.js中管理视图仍然不存在众所周知的方式,但我更喜欢全局变量的方式。这将确保您的视图实例在整个应用程序中可用,并且所有模块都可以访问它们。例如,这样做

window.App.Contacts.ContactView = new App.Contacts.View.ContactView({model:BenContact});将使视图用于通过窗口对象显示Ben的应用程序模块可用的联系信息。对于使用相同el的任何视图,您只需要销毁ContactView并呈现新视图。

  • 您可以在视图上删除它们

Undelegate事件和Remove方法可帮助您删除它们。处理路由散列更改事件的回调方法内部。例如,在处理#/!/view/all的回调方法(用于查看所有联系人列表的网址)中,您可能会遇到两个视图现在使用相同el的情况,因此您应该销毁ContactView并渲染ListView以便在回调中执行此操作

App.Contacts.ContactView.undelegateEvents();

App.Contacts.ContactView.remove();

答案 1 :(得分:1)

由于Backbone.js没有内置的视图合成支持,因此在跟踪子视图时可以遵循几种模式。

  • Derick Bailey演示了扩展Backbone.View以允许视图 自己清理干净 - http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/

  • 另一种方法是将子视图添加到该属性 父视图状态并在父视图状态为时手动清除它们 除去。

    var ParentView = Backbone.View.extend({     initialize:function(){        this.childViews = [];     },     render:function(){        this.childViews.push(new ChildView);     } });

  • 第三种方法是让子视图订阅事件 父视图触发,以便他们可以清理时 父视图发布“关闭”事件。

此外,我从您的代码中注意到您实际上是在您的子视图类中获取模型。理想情况下,我建议将模型作为参数传递给构造函数,因为这会将视图与数据分离。它更像MVC-ish