Backbone/Marionette div 包装器干扰 Select 选项

Backbone/Marionette div wrapper interfering with Select Options

我有一个布局视图,其中一个区域包含 select 输入。

//template
<div class="col-xs-12">
    <select name="type" id="drop" class="select"></select>
</div>

我有一个 LayoutView,它定义了以下区域并分配了一个集合视图以使用选项填充 select 菜单。

//layout
Backbone.Marionette.LayoutView.extend({
    regions: {drop: "#drop"},
    onRender: function() {
        this.getRegion("drop").show(new (Marionette.CollectionView.extend({
            childView: FieldView
        }))(collection: fieldCollection)));
    }
}

FieldViewfieldCollection 工作正常,但我遇到了问题。渲染时,集合子视图将选项包装在 div 标记中,从而阻止 select 菜单正常工作。

//Rendered HTML
<select name="type" id="drop" class="select">
    <div>
        <option value='1'>Option 1</option>
        <option value='2'>Option 2</option>
        <option value='3'>Option 3</option>
    </div>
</select>

关于如何摆脱那个讨厌的 div 标签有什么建议吗?子视图的 el 不应该根据区域限制在 select 元素本身吗?

由于您的问题很常见,因此经常会争论额外的 div 功能。例如,参见这个非常有趣的 issue

不幸的是,Backbone 和 Marionette 视图都知道它们的父视图,即使该父视图是 LayoutView。事实上,Marionette 继承了 Backbone 的包装器行为,并且在大多数情况下,它是视图具有的最常识性结构。

改变 CollectionViewel,危险地生活

您可以采取更危险的方式,将您的区域元素分配给 CollectionView 的 el,我在这篇 Answer 中对此进行了描述。我在那里的建议是覆盖区域的 .attachHtml() 方法,将子视图的内容(而不是 el)直接插入区域的 el,最重要的是,使用view.setElement()将子视图的el设置为区域的el。但请仔细阅读那里的警告。两个视图之间的事件将共享!你无法避免。

拥抱包装纸,拥抱Backbone

就我个人而言,我提倡合作,而不是反对Backbone/Marionette。我知道您可能有充分的理由想要在 LayoutView 中使用 <select/> 元素。 但是,如果你可以在没有那个元素的情况下生活,我可以为你提供一个非常简单快速的修复方法:你可以使用你想要的任何(适当的)HTML 元素视图的包装器。所以你的 .show() 可以看起来像这样:

onRender: function() {
  this.getRegion("drop").show(new (Marionette.CollectionView.extend({
    tagName: "select",
    attr: {
      name:"type"
    },
    id: "drop", 
    className: "select",
    childView: FieldView
  }))(collection: fieldCollection)));
}

我所做的只是将视图的香草 <div/> el 更改为

<select name="type" id="drop" class="select"></select>

别忘了,您需要为您的区域分配一个新元素。让我们以包含 <select/> 的原始 <div/> 为例,

<div class="col-xs-12" id="field-region">

</div>

访问 LayoutView 中的 <select/> 元素

<select/> 语句不是您的 CollectionView 的 el。这可能不会打扰您,但有时您可能会在 LayoutView 中执行类似 $("#drop").val() 的操作。好消息是您可以本地访问 <select/>,因为它是您传入的 CollectionView 的 el。代价是您需要保留对该视图的引用。像,

onRender: function() {
  this.fieldView = new Marionette.CollectionView.extend({
    tagName: "select",
    attr: {
      name:"type"
    },
    id: "drop", 
    className: "select",
    childView: FieldView
  });
  this.getRegion("drop").show(this.fieldView(collection: fieldCollection));
},

onSelectOption: function () {
  console.log(this.fieldView.$el.val());
}