web-dev-qa-db-ja.com

Backbone.Marionette.ItemViewのdivラップをオフにする

ここで怒っている猫のバックボーン/マリオネットのチュートリアル投稿を見ています

http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/

http://davidsulc.com/blog/2012/04/22/a-simple-backbone-marionette-tutorial-part-2/

そして私はここに投稿された同じ質問/ニーズに遭遇しました:

Backbone.jsがレンダーでdivによるラップをオフにする

ただし、Backbone.Marionette.ItemViewsではなく、Backbone.Viewsでのみ機能します。

たとえば、上記の簡単なバックボーンマリオネットチュートリアルリンクから、AngryCatViewを取得します。

AngryCatView = Backbone.Marionette.ItemView.extend({
  template: "#angry_cat-template",
  tagName: 'tr',
  className: 'angry_cat',
  ...
});

テンプレート、#angry_cat-template、次のようになります:

<script type="text/template" id="angry_cat-template">
  <td><%= rank %></td>
  <td><%= votes %></td>
  <td><%= name %></td>
  ...
</script>

私が気に入らないのは、AngryCatViewに

  tagName: 'tr',
  className: 'angry_cat',

-tagNameを取り出すと、angry_cat-template<div>

HTMLを1か所(angry_cat-template)で指定し、ほとんどのHTML(<td>タグ)とangry_cat-templateおよび小さなHTML(<tr>タグ)。これをangry_cat-templateに記述します。

<script type="text/template" id="angry_cat-template">
  <tr class="angry_cat">
    <td><%= rank %></td>
    <td><%= votes %></td>
    <td><%= name %></td>
    ...
  </tr>
</script>

それは私にはすっきりしているように感じますが、「Backbone.jsレンダリングでdivによるラップをオフにするBackbone.js」でのDerik Baileyの回答をいじくり回していて、Backbone.Marionetteで機能させることができません。

何か案は?

30
mrk

2014/02/18 —コメントで@vaughanおよび@ Thom-Nicholsが指摘した改善に対応するために更新


私のitemView/layoutsの多くでこれを行います:

_var Layout = Backbone.Marionette.Layout.extend({

    ...

    onRender: function () {
        // Get rid of that pesky wrapping-div.
        // Assumes 1 child element present in template.
        this.$el = this.$el.children();
        // Unwrap the element to prevent infinitely 
        // nesting elements during re-render.
        this.$el.unwrap();
        this.setElement(this.$el);
    }

    ...

});
_

上記のコードは、ラッパーdivに単一の要素が含まれている場合にのみ機能します。これが、テンプレートを設計する方法です。

あなたの場合、.children()は_<tr class="angry_cat">_を返すので、これは完璧に機能するはずです。

私は同意します、それはテンプレートをずっときれいに保ちます。

注意すべきこと:

この手法では、子要素が1つだけ強制されるわけではありません。これは.children()を盲目的に取得するため、3つの_<td>_要素を含む最初のテンプレートの例のように、複数の要素を返すようにテンプレートを誤って作成した場合、うまく機能しません。

ルート_<tr>_要素を持つ2番目のテンプレートと同様に、テンプレートは単一の要素を返す必要があります。

もちろん、必要に応じてこれをテストするように書くこともできます。


これは好奇心が強い人のための実用的な例です:http://codepen.io/somethingkindawierd/pen/txnpE

42
bejonbee

renderの内部をハックして思い通りの動作をさせる方法があると私は確信していますが、このアプローチを取ることは、開発全体を通してバックボーンとマリオネットの慣習と戦うことになることを意味します処理する。 ItemViewには$elが関連付けられている必要があり、divを指定しない限り、慣例により、これはtagNameです。

私は共感します-特にレイアウトとリージョンの場合、Backboneが余分な要素を生成するのを止めることは不可能のようです。フレームワークの残りの部分を学びながら、慣習を受け入れることをお勧めします。それから、renderをハッキングして、異なる動作をさせる(または、別のフレームワークを選択する)価値があるかどうかを判断します。

10
Tres

これを達成するためにjQueryの代わりにVanilla JSを使用するほうがきれいではないでしょうか?

var Layout = Backbone.Marionette.LayoutView.extend({

  ...

  onRender: function () {
    this.setElement(this.el.innerHTML);
  }

  ...

});
3
Sam Samskies

このソリューションは、再レンダリングで機能します。 renderをオーバーライドする必要があります。

onRenderトリックは、再レンダリングでは機能しません。それらはすべての再レンダリングでネストを引き起こします。

BM.ItemView::render = ->
  @isClosed = false
  @triggerMethod "before:render", this
  @triggerMethod "item:before:render", this
  data = @serializeData()
  data = @mixinTemplateHelpers(data)
  template = @getTemplate()
  html = Marionette.Renderer.render(template, data)

  #@$el.html html
  $newEl = $ html
  @$el.replaceWith $newEl
  @setElement $newEl

  @bindUIElements()
  @triggerMethod "render", this
  @triggerMethod "item:rendered", this
  this
3
vaughan

IE9 +の場合は、 firstElementChild および childElementCount を使用するだけです。

var Layout = Backbone.Marionette.LayoutView.extend({

  ...

  onRender: function () {
      if (this.el.childElementCount == 1) {
          this.setElement(this.el.firstElementChild);
      }
  }

  ...

});

Marionetteが自動的にラッパーDIVを挿入するのには十分な理由があります。ドロップできるのは、テンプレートが1つの要素のみで構成されている場合のみです。したがって、子要素の数のテスト。

別のオプションは、すべてのマリオネットビューに存在する attachElContent メソッドを使用することです。デフォルトの実装では、ビューの再レンダリングによりルート要素の内部HTMLが上書きされます。これにより、最終的にはベジョンビーの回答で言及されている無限の入れ子が生じます。

OnRenderを上書きしたくない場合や、pure-JSソリューションが必要な場合は、次のコードで十分です。

var Layout = Backbone.Marionette.LayoutView.extend({

  ...

  attachElContent: function (html) {
      var parentEl = this.el.parentElement;
      var oldEl;

      //View already attached to the DOM => re-render case => prevents
      //recursive nesting by considering template's top element as the
      //view's when re-rendering
      if (parentEl) {
          oldEl = this.el;
          this.setElement(html);                   //gets new element from parsed html
          parentEl.replaceChild(this.el, oldEl);   //updates the dom with the new element 
          return this;

      //View hasn't been attached to the DOM yet => first render 
      // => gets rid of wrapper DIV if only one child
      } else {
          Marionette.ItemView.prototype.attachElContent.call(this, html);
          if (this.el.childElementCount == 1) {
              this.setElement(this.el.firstElementChild);
          }
          return this;
      }
  }

  ...

});

再レンダリングが機能するために、コードはすべてのマークアップを含む単一の子を持つテンプレートを想定していることに注意してください。

1
hqcasanova