1

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

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

我是否需要以某种方式手动销毁以前的视图(或者这是否由路由器对象以某种方式处理)?还是在视图初始化后离开视图更好?

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

/** 
 * 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();
4

2 回答 2

2
  • 路由不会破坏视图

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

  • 视图应由开发人员管理

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

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

  • 您可以查看删除它们的方法

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

App.Contacts.ContactView.undelegateEvents();

App.Contacts.ContactView.remove();

于 2012-06-04T05:20:59.403 回答
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 风格

于 2012-06-04T05:28:18.627 回答