これは素晴らしい質問です。バックボーンは想定が不足しているため素晴らしいですが、このようなことを自分で実装する(方法を決定する)必要があることを意味します。自分のものを調べたところ、シナリオ1とシナリオ2が混在していることがわかりました。4番目の魔法のシナリオは、シナリオ1と2で行うことはすべて、完了しました。
例を挙げて、自分の扱い方を説明するのが最も簡単だと思います。この単純なページを指定されたビューに分割するとします。
HTMLは、レンダリングされた後、次のようになります。
<div id="parent">
<div id="name">Person: Kevin Peel</div>
<div id="info">
First name: <span class="first_name">Kevin</span><br />
Last name: <span class="last_name">Peel</span><br />
</div>
<div>Phone Numbers:</div>
<div id="phone_numbers">
<div>#1: 123-456-7890</div>
<div>#2: 456-789-0123</div>
</div>
</div>
うまくいけば、HTMLが図とどのように一致するかはかなり明白です。
ParentView
2つのビューを保持している、InfoView
とPhoneListView
だけでなく、いくつかの余分なdiv要素の一つ、#name
いくつかの点に設定する必要があります。 エントリのPhoneListView
配列である独自の子ビューを保持しPhoneView
ます。
では、実際の質問に移ります。ビューのタイプに基づいて、初期化とレンダリングを異なる方法で処理します。私は自分の見解を2つのタイプ、Parent
ビューとChild
ビューに分けます。
それらの違いは単純です。Parent
ビューは子ビューを保持しますが、ビューは保持Child
しません。したがって、私の例ではParentView
、PhoneListView
はParent
ビューですが、InfoView
およびPhoneView
エントリはChild
ビューです。
前に述べたように、これら2つのカテゴリの最大の違いは、レンダリングが許可されるタイミングです。完璧な世界では、Parent
ビューを一度だけレンダリングしたいです。モデルが変更されたときに再レンダリングを処理するのは、子ビュー次第です。Child
一方、ビューには、他のビューに依存するビューがないため、必要なときにいつでも再レンダリングできます。
もう少し詳しく説明すると、Parent
ビューでは、initialize
関数がいくつかのことをするのが好きです。
- 自分のビューを初期化する
- 自分のビューをレンダリングする
- 子ビューを作成して初期化します。
- 各子ビューにビュー内の要素を割り当てます(たとえば、
InfoView
が割り当てられます#info
)。
ステップ1は自明です。
ステップ2、レンダリングは、子ビューが依存する要素が割り当てられる前にすでに存在するように行われます。これを行うことで、すべての子events
が正しく設定されることがわかっているので、何も再委譲する必要を心配することなく、必要なだけ何度でもそれらのブロックを再レンダリングできます。render
ここでは実際には子のビューはありませんinitialization
。自分の中でそれを行うことを許可します。
手順3と4はel
、子ビューの作成中に渡すと同時に実際に処理されます。親が自分のビューで子がコンテンツを配置できる場所を決定する必要があると思うので、ここに要素を渡したいと思います。
レンダリングについては、Parent
ビューではかなりシンプルに保つようにしています。render
親ビューをレンダリングする以外に何もしないようにしたいのですが。イベントの委任、子ビューのレンダリング、何もありません。単純なレンダリング。
ただし、これが常に機能するとは限りません。たとえば、上記の例#name
では、モデル内の名前が変更されるたびに要素を更新する必要があります。ただし、このブロックはParentView
テンプレートの一部であり、専用のChild
ビューでは処理されないため、回避します。要素のコンテンツを置き換えるだけで、要素全体を破棄する必要のない、ある種のsubRender
関数を作成します。これはハックのように思えるかもしれませんが、DOM全体の再レンダリングや要素の再接続などを心配する必要があるよりも、うまく機能することがわかりました。本当にクリーンにしたい場合は、ブロックを処理する(と同様の)新しいビューを作成します。#name
#parent
Child
InfoView
#name
Child
ビューの場合、これはビューinitialization
とかなり似ていParent
ますが、それ以上Child
ビューを作成する必要はありません。そう:
- ビューを初期化する
- セットアップは、気になるモデルへの変更のリスニングをバインドします
- ビューをレンダリングする
Child
ビューのレンダリングも非常に単純で、レンダリングしてmyのコンテンツを設定するだけel
です。繰り返しになりますが、委任などをいじる必要はありません。
ここに私ParentView
がどのように見えるかのいくつかのサンプルコードがあります:
var ParentView = Backbone.View.extend({
el: "#parent",
initialize: function() {
// Step 1, (init) I want to know anytime the name changes
this.model.bind("change:first_name", this.subRender, this);
this.model.bind("change:last_name", this.subRender, this);
// Step 2, render my own view
this.render();
// Step 3/4, create the children and assign elements
this.infoView = new InfoView({el: "#info", model: this.model});
this.phoneListView = new PhoneListView({el: "#phone_numbers", model: this.model});
},
render: function() {
// Render my template
this.$el.html(this.template());
// Render the name
this.subRender();
},
subRender: function() {
// Set our name block and only our name block
$("#name").html("Person: " + this.model.first_name + " " + this.model.last_name);
}
});
subRender
ここで私の実装を見ることができます。のsubRender
代わりにバインドされた変更を使用することでrender
、ブロック全体を爆破して再構築することを心配する必要はありません。
InfoView
ブロックのサンプルコードは次のとおりです。
var InfoView = Backbone.View.extend({
initialize: function() {
// I want to re-render on changes
this.model.bind("change", this.render, this);
// Render
this.render();
},
render: function() {
// Just render my template
this.$el.html(this.template());
}
});
バインドはここで重要な部分です。モデルにバインドすることで、手動でrender
自分を呼び出すことを心配する必要がなくなります。モデルが変更されると、このブロックは他のビューに影響を与えることなく、自身を再レンダリングします。
これPhoneListView
はに似ていParentView
ます。コレクションを処理するにはinitialization
、render
関数と関数の両方にもう少しロジックが必要です。コレクションの処理方法は実際にはあなた次第ですが、少なくともコレクションイベントをリッスンし、どのようにレンダリングするか(追加/削除、またはブロック全体を再レンダリングする)を決定する必要があります。私は個人的には、新しいビューを追加して古いビューを削除するのが好きです。ビュー全体を再レンダリングするのではありません。
PhoneView
ほぼ同じになるInfoView
だけで、それが気にモデルチェンジを聞いて、。
これで少しは助かったと思いますが、混乱していたり詳細が十分でない場合はお知らせください。