【问题标题】:How to show CompositeView with multiple children view in Backbone Marionette如何在 Backbone Marionette 中显示具有多个子视图的 CompositeView
【发布时间】:2013-09-12 09:44:33
【问题描述】:

开始的问题

我有一个 CompositeView(一个表),集合中的每个模型都表示为两个表行,模板如下:

<tr class="row-parent">
    <td>parent info here</td>
</tr>
<tr class="row-child">
    <td>child info here</td>
</tr>

使用这样的 ItemView:

var ItemView = Backbone.Marionette.ItemView.extend({
    template: ItemTmpl
});

尽管它们被命名为“父”和“子”,但它们实际上是同一模型的对等成员。如果我不指定 tagName,Backbone 会将每个视图包装在 &lt;div&gt; 中,这既是无效的 HTML,也会破坏布局。

第一次尝试解决方案

所以我想,为什么不删除外部的 &lt;tr&gt; 标签并让 Backbone 添加它们。所以我将模板更新为:

    <td>parent info here</td>
</tr>
<tr class="row-child">
    <td>child info here</td>

并将视图更新为:

var ItemView = Backbone.Marionette.ItemView.extend({
    template: ItemTmpl,
    tagName: 'tr',
    className: 'row-parent'
});

我希望外部标签可以与内部标签片段结合,但 Marionette 不喜欢这样。它只显示了row-child。所以我不确定从这里去哪里。我正在考虑两种策略,但还没有详细说明。

前进:A 计划

覆盖 Backbone 的任何部分创建额外的 div 以不创建它,或覆盖 Marionette 附加视图的部分以在附加之前删除 div。

前进:B 计划

创建一种称为 CompositeMultiView 的新视图类型,它自然会从 CompositeView 扩展,并允许您两个指定第二个 ItemView,或者可能只是一个视图数组,所有这些都将为给定的每个模型呈现。这个计划似乎需要做更多的工作,但受到的黑客攻击更少。


对于我将如何实施上述两个计划中的任何一个,是否有人有更好的建议、解决方法或具体指示?

下面是表格的样机:

【问题讨论】:

  • 乍一看,我肯定会选择 B 计划。另外,您能否举一个粗略的例子说明您正在处理哪种数据结构?我想确认CompositeView 在这里最好。
  • 嗯,我不认为数据结构特别不寻常或复杂。它只是一系列模型。我认为 CompositeView 是合适的,因为我想在表格(分支)中显示模型(叶子),这几乎就是 CompositeView 的发明目的。唯一不寻常的部分是一个表格行中要表示的数据太多,所以我想将其显示为两个表格行。
  • 听我说,@T Nguyen。如果它是一组平面模型并显示为两行,我认为不需要CompositeView。您可以只拥有一个带有模板的 ItemView,该模板将数据分布在两个表行中。 CompositeView 如果您列出嵌套数据(例如文件夹结构或通过类别列出的项目列表)更有意义。
  • CMIIW,但如果我这样做,我只会得到一个巨型模型。如果不编写我自己的自定义代码来执行此操作,我将无法添加、更新或删除集合中的单个模型。如果可能的话,我想把这一切都用“骨干方式”来做。
  • 那我误解了您的数据设置方式。一个模型 = 两个&lt;tr&gt;s?如果是这样,您将拥有一个代表一个模型的 ItemView,然后将模型集合分配给 CollectionView

标签: javascript backbone.js marionette


【解决方案1】:

您可以尝试如下修改 CompositeView:

  1. itemView 指定为视图数组
  2. 覆盖 addChildView 以呈现每个模型的每个视图

这个解决方案最终看起来很像您的“B 计划”。试一试:

itemView: [My.ParentView, My.ChildView],

addChildView: function(item, collection, options){
  this.closeEmptyView();
  var itemViews = this.getItemView(item);
  var index = this.collection.indexOf(item);

  _.each(itemViews, function(ItemView) {
    this.addItemView(item, ItemView, index);
  });
}

我还没有考虑过这是否会处理诸如destroy 之类的模型事件,但我相信它应该能够优雅地处理它们。

【讨论】:

  • 感谢您指向正确方向的指针。我会尝试并报告。
  • @EML:在大多数情况下,我只拥有一个 itemView,但我确实有一个场景,每个 itemView 都有一个子视图。不过,这是与上面不同的实现。我会看看我是否可以为你整理一个 jsFiddle 示例。
【解决方案2】:

肮脏的解决方案:向您的 ItemView 添加自定义渲染函数

// Or whatever template you use
var template = Handlebars.compile(datepickerTemplate);

var ItemView = Backbone.Marionette.ItemView.extend({
    render: function(){
        var html = template(this.model.toJSON());
        var newElement = $(html);
        this.$el.replaceWith(newElement);
        this.setElement(newElement);
        return this;
    }
});

这应该删除额外的 div 包装

【讨论】:

  • 是的,这几乎就是 Plan A 并且实际上是我现在正在使用的解决方案。除了,我将代码添加到 CompositeViewappendHtml() 方法中,但它相当于同一件事。然而,正如我向 Chris 提到的,我仍然认为这是一个有效的、普遍化的问题,我有兴趣开发一个更优雅和“适当”的长期解决方案。我认为 Plan B 就是那个解决方案,但我还没有机会研究它。谢谢。
  • 我很想知道这会对视图的事件绑定产生什么影响。请在@TNguyen 发布您的发现。
【解决方案3】:

我一直在为同样的问题苦苦挣扎,直到今天我终于发现,一个表可以有多个 tbody 标签,每个标签都包含多个 tr 标签。

这实际上是 the answer 提供给一个类似的主干问题。

所以你的ItemView 会变成:

var ItemView = Backbone.Marionette.ItemView.extend({
    template: ItemTmpl,
    tagName: 'tbody'
});

以及生成的html:

<table>
  <!-- first item -->
  <tbody>
    <tr class="row-parent">
      <td>parent info here</td>
    </tr>
    <tr class="row-child">
      <td>child info here</td>
    </tr>
  </tbody>
  <!-- second item -->
  <tbody>
    <tr class="row-parent">
      <td>parent info here</td>
    </tr>
    <tr class="row-child">
      <td>child info here</td>
    </tr>
  </tbody>
  ...
</table>

【讨论】:

  • 其实,我应该更新我的问题,但这也是我的解决方案。
  • 这很优雅。恕我直言,应该是公认的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多