我将从一个明确的问题开始,然后解释:
如何将包含在 CompositeView 中的模型正确封装到 ItemView
我的问题很简单,但我无法设法得到一些好的工作。
我有一棵笔记树。
每个音符都是一个 Backbone.model 并且有一个 @descendants 集合,
然后我有一个 Backbone.Collection 来代表那棵树(其中@descendants 是一个实例)
我设置了一个基本的 CollectionView ,作为 itemViewCompositeView 。一切都完美呈现,我对此感到非常高兴。这个有效的解决方案显示在第一个代码片段中!
问题来了。在此基础上,我有点遇到了这个问题:Events fired for whole hierarchy
这对于我的事件如何绑定(bind)是有意义的。起初,我只是添加了唯一的选择器(向我的 html 元素添加了 data-guid,以便我可以通过它来获取它们)并且它工作正常,尽管它已经变得“hacky”了。但是其他类似的问题已经出现,所以我决定我需要一个解决方案。
所以,我告诉 myslef,让我们将每个模型封装在一个 ItemView 中,并使用 Composite View 来递归渲染它们。
但是......这并不是世界上最好的......
这是我一开始所拥有的:

class Note.ModelView extends Marionette.CompositeView
  template: "note/noteModel"
  id: "note-item"
  itemViewContainer: ".note-descendants"
  ui:
    noteContent: ".noteContent"
  events:
    "keypress .noteContent": "createNote"
    "click .destroy": "deleteNote"
  # ...
  initialize: ->
    @collection = @model.descendants
  # ...

class Note.CollectionView extends Marionette.CollectionView
  id: "note-list"
  itemView: Note.ModelView
  initialize: ->
    @listenTo @collection, "sort", @render
现在我转移了所有属于在新的 ItemView 中渲染模型的东西
  class Note.ModelView extends Marionette.ItemView
    template: "note/noteModel"

    ui:
      noteContent: ".noteContent"
    events: ->
      guid = @model.get 'guid'
      events = {}
      events["keypress #noteContent#{guid}"] = "createNote"
      events["blur #noteContent#{guid}"] = "updateNote"
      events["click #destroy#{guid}"] = @triggerEvent 'deleteNote'

    initialize: ->
      @bindKeyboardShortcuts()
      @listenTo @model, "change:created_at", @setCursor

  class Note.TreeView extends Marionette.CompositeView
    template: "note/parentNote"
    itemView: Note.ModelView

    initialize: ->
      @collection = @model.descendants
      @listenTo @collection, "sort", @render
      _.bindAll @, "renderItem"
    renderItem: (model) ->
      if model.get('parent_id') is 'root'
        itemView = new Note.ModelView model: model
        itemView.render()
        @$el.append itemView.el
    onRender: ->
      @collection.each this.renderItem
      @renderItem @model
    appendHtml: (collectionView, itemView) ->
      @model.descendants.each (note) =>
        iv = new Note.ModelView model: note
        iv.render()
        @.$('.note-descendants').append iv.el


  class Note.CollectionView extends Marionette.CollectionView
    id: "note-list"
    itemView: Note.TreeView
    initialize: ->
      @listenTo @collection, "sort", @render
和 noteMode 模板(parentNote 现在只是一个空模板)
<button class="btn btn-danger btn-xs untab">UN</button>
<button class="btn btn-success btn-xs tab">TAB</button>
<div class="noteContent">{{{indent}}}{{{title}}}</div>
<button class="destroy"></button>
<div class="note-descendants"></div> # That is where I'm putting the children notes
所以这几乎是有效的。但它是hacky 并且.. 好吧,它仍然不能正常工作。我一直在阅读所有文档,并且我已经阅读了 Derick Bailey on nested structure and CompositeViewDavid Sulc on Nested Views 这两个链接,但我仍然觉得我遗漏了一些重要的细节。
作为答案,我正在寻找的是任何提示或使用 Marionette 管理此问题的任何常用方法。我真的在寻找干净的东西,因为这将成为构建应用程序的 Angular 部分之一。
也许我也在错误的地方搜索?任何东西都会受欢迎!!非常感谢你
祝大家度过一个愉快的夜晚。
感谢您的时间。

最佳答案

我将用不同的语言向您解释 Derick Bailey 在您引用的博客文章中已经说过的内容。

View

您需要两个 View 来完成这项工作。

第一个,“母 View ”,是包含递归结构作为其子节点的最外层 View 。这可能是 Marionette.CollectionView 或 Marionette.CompositeView。

第二个 View 是您的递归 View ,这意味着它必须是 Marionette.CompositeView。通过不指定“itemView”属性,您可以使 Marionette.CompositeView 递归。由于缺少 itemView 属性,Marionette.CompositeView 将使用 ITSELF 来呈现给定的集合的模型。

收藏

您需要一个集合,它要么是嵌套 Backbone.Collections 的 Backbone.Collection,要么只是包含深度嵌套哈希的 Backbone.Collection。在后一种情况下,在将简单哈希传递给 Marionette.CompositeView 时,您不必忘记将它们转换为 Backbone.Collections(如下面在 RecursiveView 的 initialize() 方法中所做的那样)。

将所有内容放在一起

var RecursiveView = Marionette.CompositeView.extend({
    template: '#someTemplate',
    initialize: function () {
        this.collection = this.model.get('children')
    }
});

var MotherView = Marionette.CollectionView.extend({
    itemView: RecursiveView,
    collection: new Backbone.Collection([{key: 'value', children: [{}, {}, {}]}])
});

问题:事件冒泡

自然,DOM 事件现在会冒泡,所以这段代码
var RecursiveView = Marionette.CompositeView.extend({
    events: {
        'click button': someCallback
    }
});

将是它引用的 View 及其所有后代的事件的全部。

这个问题最简单的解决方案是使用直接后代 css 选择器 > ,例如
var RecursiveView = Marionette.CompositeView.extend({
    events: {
        'click >button': someCallback
    }
});

如果这还不够,一种有效的解决方案是防止自动事件冒泡,例如
var RecursiveView = Marionette.CompositeView.extend({
    events: {
        'click button': function (event) {
            event.stopPropagation();
            // or event.stopImmediatePropagation() depending on your use case
            // cf. http://stackoverflow.com/a/5299841/899586 and
        }
    }
});

关于javascript - 使用 CompositeView 渲染递归结构,同时使用 Marionette 将每个模型封装在 ItemView 中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19238184/

10-08 21:57