使用主干.js中的路由管理单页应用程序中的多个视图实例

Managing multiple instances of views in one page apps using Routes in Backbone.js

本文关键字:应用程序 实例 视图 单页 路由 js 管理      更新时间:2023-09-26

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

在我的应用程序中,许多视图负责显示特定的"页面",因此共享相同的 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();
  • 路由不会破坏视图

路由为您提供了与 url 更改进行交互的便捷方式。通过方便,我的意思是当前页面的 url 语义和上下文。例如,url #/!/create/将调用一个方法,该方法应显示用于创建模型的窗体。此处的上下文是用于创建模型的视图。

  • 视图应由开发人员管理

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

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

  • 您有删除它们的方法

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

App.Contacts.ContactView.undelegateEvents();

App.Contacts.ContactView.remove();

由于 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({ 初始化 : 函数(){ this.childViews = []; }, 渲染: 函数(){ this.childViews.push(new ChildView); }});

  • 第三种选择是让子视图订阅事件父视图触发,以便他们可以在父视图发布"关闭"事件。

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