2

我有一个项目清单。它们存储在骨干可分页集合中。

它们是这样显示的

|---item1---------------|
|---项目2---------------|
|---项目3---------------|
|---item4---------------|
|---item5---------------|
|---第 6 项---------------|
|---第 7 项---------------|
<< 1,2,3...结束>>

用户可以单击单个项目以在单独的页面中打开详细视图。详细视图在创建时已初始化侦听器。这些侦听器绑定到项目模型。

由于详细视图很大,我通过切换可见性将其缓存在 DOM 中。随后单击该项目将切换缓存视图。

------问题来了-----

当项目列表切换到另一个页面时,集合被重置(通过分页器)。并且之前存储在集合中的所有模型都被取消引用,并创建了一组新模型。所以页面来回切换后,之前打开的item就有了自己不同的副本存储在collection中。因此,当我在详细视图(在视图缓存中)更改项目名称时,项目列表中的名称不会更改。

观点不同步!因为它们引用了不同的模型。

不确定其他人是否遇到过这种情况。如果你这样做,请与我分享你是如何解决它的。

非常感谢。

4

1 回答 1

1

在页面更改时,在列表视图项和相应的详细视图之间保持新引用的最直接方法是重新渲染详细视图。但我假设这个选项在您的项目范围内是不可接受的。

当我有在逻辑上分离的视图中形成关系的任务时,我经常做的是使用监听器。只要视图共享一个唯一标识符(例如,它们都共享一个模型,或至少相同的模型 ID),我总是可以发送一条消息,该消息将到达我感兴趣的视图。

为此,您需要一个集中的事件中心,使用 Backbone 很容易生成。在某些适当的全局变量中(例如,MyApp),我们只需执行以下操作:

MyApp.EventBus = _.extend({}, Backbone.Events);

设置详细视图

在详细视图初始化函数上,我将删除此侦听器,

initialize: function () {
  // Listen to a toggle visibility on this view
  this.listenTo(MyApp.EventBus, 'detail-view:toggle-view', toggleView);
},

toggleView: function (id) {
  if (this.model.id == id) {
     // Show this view if I have the passed id
     this.$el.show()
     // Notify the parent list item view that its detail view exists
     MyApp.EventBus.trigger('detail:view:exists', true);
  } else {
    // Hide all other views
    this.$el.hide();
  }
},

changeName: function () {
  // logic that parses DOM user input to 
  // local variable name

  // We now trigger an event 'detail-view:change:name', and we send as 
  // parameters our model's id and the new name
  MyApp.EventBus.trigger('detail-view:change:name', this.model.id, name);
}

设置列表项视图

列表项视图将希望监听名称更改(或您希望列表项知道的详细视图中的任何其他模型属性)。所以我们将为 'detail-view:change:name' 事件设置一个处理程序。

我们还想连接我们的点击处理程序来切换列表项详细视图的可见性。棘手的部分是处理尚未呈现视图的事件(我假设您延迟加载详细视图)。detail:view:exists因此,我们为细节视图在捕获事件时触发的事件设置了第二个侦听器detail-view:toggle-view。如果我们没有detail:view:exists及时从目标详细视图中听到事件(我使用的是 100 毫秒,但您可以根据自己的需要进行调整),然后我们渲染视图。

initialize: function () {
  // Listen to when the detail associated with this list item changes
  // the the list item name
  this.listenTo(MyApp.EventBus, 'detail-view:change:name', onNameChange);
  // Set a property in this view if its detail view exists
  this.listenTo(MyApp.EventBus, 'detail:view:exists', 
    _.bind(function () { this.detailViewExists = true; }, this));
  // Create a debounced function that tests whether this view's
  // detail view exists
  _.debounce(_.bind(this.handleViewState, this), 100);
},

events {
  click: 'toggleDetailView'
},

toggleDetailView: function (id) {
  MyApp.EventBus.trigger('detail-view:toggle-view', this.model.id);
  this.handleViewState();
},

// Debounced function that will wait 100ms asynchronously for the 
// detail view to respond. If the detailViewExists bit is not set to true 
// then we assume the view does not exist and we render it
handleViewState: function () {
  if (!this.detailViewExists) 
     // The view does not exist, render and attach the view

  // Set the bit to false to allow testing in the event that the detail view
  // is destroyed in the future
  this.detailViewExists = false;
},

changeName: function (id, newname) {
  if (this.model.id == id) {
     // Change the name of this list item view
     this.$('.item-name').text(newname);
}

外卖

现在,这两个不同视图之间的引用是共享的唯一标识符。因为,根据设计,这两个标识符在其范围内是唯一的,并且不应更改,并且假设详细视图已被渲染并附加到 DOM,那么无论渲染其状态如何,列表项视图都将始终能够通信及其详细视图。

于 2015-05-03T14:02:13.030 回答