私のアプリケーションでは、ネストされたビューの設定がかなり深くなることがあります。サブビューの初期化、レンダリング、追加については、さまざまな方法が考えられますが、一般的な方法は何なのか疑問に思っています。
私が考えたものをいくつか挙げます:
initialize : function () {
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template());
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
長所:追加時に正しい DOM 順序を維持することを心配する必要はありません。ビューは早い段階で初期化されるため、レンダリング関数で一度に行う処理はそれほど多くありません。
短所:コストがかかる可能性がある、delegateEvents() を再度実行する必要がありますか? 親ビューのレンダリング関数は、実行する必要があるすべてのサブビューのレンダリングで乱雑になっていますか? 要素を設定する機能がないtagName
ため、テンプレートは正しい tagNames を維持する必要があります。
別の方法:
initialize : function () {
},
render : function () {
this.$el.empty();
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
this.$el.append(this.subView1.render().el, this.subView2.render().el);
}
長所:イベントを再度委任する必要はありません。空のプレースホルダーだけを含むテンプレートは必要なく、tagName はビューによって定義されるようになります。
短所:ここで、正しい順序で追加することを確認する必要があります。親ビューのレンダリングは、サブビューのレンダリングによってまだ乱雑になっています。
イベントの場合onRender
:
initialize : function () {
this.on('render', this.onRender);
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
長所:サブビューのロジックはビューのrender()
メソッドから分離されました。
イベントの場合onRender
:
initialize : function () {
this.on('render', this.onRender);
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1 = new Subview();
this.subView2 = new Subview();
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
これらすべての例では、さまざまなプラクティスを混ぜ合わせていますが (申し訳ありません)、保持または追加するものは何ですか? また、行わないものは何ですか?
実践の概要:
- または でサブビューをインスタンス化します
initialize
かrender
? - すべてのサブビュー レンダリング ロジックを または
render
で実行しますかonRender
? setElement
または を使用しますかappend/appendTo
?
ベストアンサー1
私は一般的に、いくつかの異なる解決策を見たり使用したりしてきました。
解決策1
var OuterView = Backbone.View.extend({
initialize: function() {
this.inner = new InnerView();
},
render: function() {
this.$el.html(template); // or this.$el.empty() if you have no template
this.$el.append(this.inner.$el);
this.inner.render();
}
});
var InnerView = Backbone.View.extend({
render: function() {
this.$el.html(template);
this.delegateEvents();
}
});
これは最初の例と似ていますが、いくつか変更があります。
- サブ要素を追加する順序は重要です
- 外部ビューには、内部ビューに設定される HTML 要素が含まれていません (つまり、内部ビューで tagName を指定できます)
render()
内部ビューの要素が DOM に配置された後に呼び出されます。これは、内部ビューのrender()
メソッドが他の要素の位置/サイズに基づいてページ上に配置/サイズ設定する場合に役立ちます (これは私の経験では一般的な使用例です)。
解決策2
var OuterView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
this.$el.html(template); // or this.$el.empty() if you have no template
this.inner = new InnerView();
this.$el.append(this.inner.$el);
}
});
var InnerView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
this.$el.html(template);
}
});
解決策 2 はよりきれいに見えるかもしれませんが、私の経験では奇妙なことが発生し、パフォーマンスに悪影響を与えました。
私は通常、いくつかの理由からソリューション 1 を使用します。
render()
私のビューの多くは、メソッド内で既にDOM内にあることを前提としています- 外側のビューが再レンダリングされるとき、ビューを再初期化する必要はありません。再初期化はメモリリークを引き起こし、既存のバインディングで奇妙な問題を引き起こす可能性があります。
new View()
が呼び出されるたびに初期化する場合render()
、その初期化はいずれにせよ呼び出されることに留意してくださいdelegateEvents()
。したがって、あなたが述べたように、それは必ずしも「欠点」ではありません。