Backbone:同一模型的多个视图模型

Posted

技术标签:

【中文标题】Backbone:同一模型的多个视图模型【英文标题】:Backbone: multiple View Models for the same model 【发布时间】:2012-01-25 17:33:30 【问题描述】:

新手主干问题:

上下文:建立一个有骨干的购物清单

我有一个带有名称、描述和标签(数组)属性的模型类。 我想基于这个模型或这个模型的集合创建两个视图。

第一个视图将显示所有项目,如下所示:

<ul>
<li><h3>Item 1 Name</h3>
<p>Item 1 Description</p>
<p>Tag1, Tag2 ,Tag3</p>
</li>
.......
</ul>

第二个视图将显示标签列表和标记项目的数量,如下所示:

<ul>
<li>Tag1<span>count of items tagged with tag1</span></li>
<li>Tag2<span>count of items tagged with tag2</span></li>
<li>Tag3<span>count of items tagged with tag3</span></li>
</ul>

我构建了模型、集合和视图来支持第一个视图。我想知道使用现有模型(或创建新模型?)构建第二个视图的正确方法。

提前谢谢...

现有的 Item 模型和集合(从 Todo.js 示例中提取)

window.Item = Backbone.Model.extend(
// Default attributes for a todo item.
defaults: function() 
return 
order: Items.nextOrder()
;

);


window.ItemList = Backbone.Collection.extend(

model: Item,

localStorage: new Store("items"),

nextOrder: function() 
  if (!this.length) return 1;
  return this.last().get('order') + 1;
,

comparator: function(item) 
  return item.get('order');


);

更新:尽管在显示带有项目计数的标签名称时覆盖 parse() 方法有效,但在添加新项目后我无法刷新标签名称/项目计数列表。这可能是由于视图是从不同的集合呈现的。我将尝试扩展 ItemList 集合并覆盖 parse() 方法。非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

@machineghost 是正确的;模型与视图完全分离,因此您可以根据需要将任意数量的视图附加到同一模型。如果视图具有您想要共享的逻辑或属性,您还可以扩展视图。当我使用 Backbone 时,我经常发现自己扩展父视图只是为了覆盖 render 函数,或者提供不同的模板。

第一次查看

ShoppingCartView = Backbone.View.extend(
  model: ShoppingCart
  ...
);

第二个独立视图

CheckoutView = Backbone.View.extend(
  model: ShoppingCart
  ...
);

第二个视图先扩展

CheckoutView = ShoppingCartView.extend( 
  template: a_different_template // syntax depends on your templating framework
  ... 
);

【讨论】:

感谢您的信息。更多背景信息:我已经使用 localStorage 示例修改了 Todo.js 以满足我的需要。目前,item 以这种格式存储在 localStorage 中:name: "Item1", description: "Item1 Desc", tags: ["Tag1", "Tag2", "Tag3"]。因此, fetch() 调用以这种格式检索。我想将此格式转换(映射)为 tagName:“Tag1”,tagCount:“3”。我相信我可以用下划线的 map 方法做到这一点。但是,我不清楚我应该把那段代码放在哪里。【参考方案2】:

我自己对 Backbone.js 还很陌生,所以对这个答案持保留态度,但我认为......你只是提出了第二个观点。解耦模型和视图的全部意义在于,如果您只想对视图做一些不同的事情,您就不需要对模型做任何事情。

所以,我认为您只需要创建 YourView2,告诉它使用与 YourView1 相同的模型,然后您就可以开展业务了。

【讨论】:

你不认为第二个视图需要它自己的模型吗?这不像我在显示具有稍微不同模板的相同模型。我需要按标签名称获取项目数量。理想情况下,第二个视图将使用这样的模型:tagName:"Tag1", tagCount:"4" 我不清楚为什么需要(甚至鼓励)制作一个单独的模型。您不能只在现有模型中添加一个 tagCount,然后在视图 #2 中重新使用它吗?一般来说(在任何 MVC 范式中),您应该只需要使用一个新模型来表示一个新事物。如果您只想稍微不同地表示旧的东西,您可以修改原始模型(或者,如果您出于某种原因真的不想这样做,例如原始模型已经有一百万行,您总是可以子类化原始模型...)。 我看不出将 tagCount 添加到现有模型会有什么帮助。然后,每个项目都有一个 tagCount 属性。给定一个项目列表,我想显示标签名称和带有该标签的项目数量。有点像 SQL 中的 GROUP BY 子句。 哦,我误会了。在这种情况下,为什么不直接将功能添加到您的集合 (ItemList) 中? 因为我需要在一个页面中显示所有项目,并在另一个页面上按标签名称进行项目计数。【参考方案3】:

Backbone.js 谷歌小组的 Paul Yoder 提供了解决方案。 你可以查看here

【讨论】:

【参考方案4】:

经过一番研究,我发现Collection.Parse 方法似乎是在 fetch() 操作后转换响应的正确位置。看起来我需要一个新的集合模型、集合和视图对象。这就是我在我的集​​合对象中实现解析函数的方式。在 Chrome 中测试成功。欢迎提出改进建议

    <snip>
    parse: function(response) 

        var items = response; //the raw item model returned from localStorage  
        var tagNameItemCount = [];
        var selectedTags = ["Tag1", "Tag2", "Tag3"];
        for(i = 0; i < selectedTags.length; i++)
            var currentTagName = selectedTags[i];
            var currentItemCount = this.getItemsCountByTagName(currentTagName, items);
            tagNameItemCount.push(tagName: currentTagName, tagCount: currentItemCount);
        

        return tagNameItemCount;



       ,
getItemsCountByTagName: function (tagName, items) 
                        var taggedItems = _.filter(items, function(item) return _.include(item.tags, tagName); );
                        return taggedItems.length;
                       ,

     </snip>

【讨论】:

在创建新的视图/集合并覆盖解析以用于显示目的时,在修改 Items 集合后视图不会刷新。更新了问题以反映此问题。

以上是关于Backbone:同一模型的多个视图模型的主要内容,如果未能解决你的问题,请参考以下文章

Backbone:删除模型而不丢失视图

使用backbone.js 从视图访问模型数据

模型和集合到 Backbone 中的一个视图

如何加载多个依赖的主干模型?

Backbone.js 将两个不同的模型添加到同一个集合中

在 Backbone 应用程序中,按照惯例,模型、视图和集合的工作是啥