javascript - 使用 CompositeView 呈现递归结构,同时使用 Marionette 将每个模型封装在 ItemView 中

标签 javascript backbone.js recursion marionette

我将从一个明确的问题开始,然后再解释:
如何将包含在 CompositeView 中的模型正确封装到 ItemView

我的问题很简单,但我无法设法使某些东西正常工作。 我有一棵笔记树。 每个笔记都是一个 Backbone.model 并且有一个 @descendants 集合, 然后我有一个 Backbone.Collection 来表示那棵树(@descendants 是其中的一个实例) 我设置了一个基本的 CollectionView,作为 itemViewCompositeView。一切都完美呈现,我对此感到非常高兴。这个有效的解决方案显示在第一段代码中!

问题来了。在此基础上,我遇到了这个问题:Events fired for whole hierarchy 这对于我的事件如何绑定(bind)是有意义的。起初,我只是添加了独特的选择器(将 data-guid 添加到我的 html 元素中,以便我可以通过它获取它们)并且它工作正常,尽管它已经变得“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

所以这几乎是可行的。但它很老套而且..它仍然不太管用。我一直在阅读所有文档,并且我已经阅读了这两个链接 Derick Bailey on nested structure and CompositeViewDavid Sulc on Nested Views但我仍然觉得我遗漏了一些重要的细节。

作为答案,我正在寻找的是使用 Marionette 进行管理的任何提示或任何常用方法。我真的在寻找干净的东西,因为这将成为应用程序构建的 Angular 之一。
也许我也在错误的地方搜索?什么都欢迎!!非常感谢

祝大家度过一个愉快的夜晚。 感谢您的宝贵时间。

最佳答案

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

观看次数

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

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

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

收藏

您需要一个集合,它可以是嵌套的 Backbone.Collection 的 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/

相关文章:

javascript - 将javascript变量分配给twig变量symfony 2

javascript - Express-获取router.get返回json数据属性

javascript - 更新主干模型/ View 的轮询请求

javascript - 主干 Web 应用程序架构 - 最佳实践

sql - 如何在递归SQL查询中找到子树中的所有节点?

javascript - 无法在 componentDidMount 内设置状态

javascript - Owl Carousel 不适用于 Rails

jquery - 如何使用backbone.js保存集合

algorithm - 在 Clojure 中实现 Minimax 算法 - 具有多个递归调用的条件函数

python - 汉诺塔递归调用