これは SO に関する私の最初の質問なので、混乱していないことを願っています。この問題に関する他のトピックを確認しましたが、私が抱えているケースはカバーされていません。
モバイル アプリケーションを作成するために、Backbone の上にライブラリを構築しています。すべてのコンポーネントをバックボーン ビューとして定義している主な理由は、スクロール時にメモリの最適化を行いたいためです (コンテンツを非表示にしたり、DOM からコンテンツを削除したりします)。
最も理想的な状況となる定義から始めましょう
すべてのコンポーネントで必要ないくつかのデフォルト プロパティといくつかの便利なメソッドを使用して、他のコンポーネントが使用する基本クラスを定義します。
UI.Component = Backbone.View.extend({
viewOptions: ['children'],
children: [],
add: function(child) {
this.children.push(child);
}
});
いくつかのデフォルト プロパティでコンポーネントを定義する
UI.Header = UI.Component.extend({
viewOptions: ['titleBarChildren', 'secondaryBarChildren', 'title', 'backButtonTitle'],
titleBarChildren: [],
secondaryBarChildren: [],
title: '',
backButtonTitle: 'Back'
});
アプリケーションで使用するデフォルトのヘッダーを作成する
MyApp.Headers.Default = UI.Header.extend({
backButtonTitle: 'Terug',
titleBarChildren: [
new UI.SegmentedController({
children: [
new UI.Button('Lame example')
]
})
]
});
ナビゲーションバーの使用
var homePageNavbar = new MyApp.Header.Default({
title: 'Homepage'
});
さあ、走ろう
console.log(homePageNavbar);
そして、この出力が得られると想像してください
// My properties, all nicely inherited
viewOptions: Array[5] //['children', 'titleBarChildren', 'secondaryBarChildren', 'title', 'backButtonTitle']
children: Array[0],
titleBarChildren: Array[1],
secondaryBarChildren: Array[0],
title: "Homepage",
backButtonTitle: "Terug"
// Some stuff that backbone assigns
$el: jQuery.fn.jQuery.init[1]
cid: "view12"
el: HTMLDivElement
options: Object
__proto__: ctor
それが私が最終的に得ようとしている結果ですが、これには私の経験を超えた魔法が必要です。
余談ですが、すべてのカスタム要素に「オプション」プロパティを使用しようとしましたが、複数のビューインスタンスを作成すると、オプションが「共有」/相互参照されるという問題があります。
だから今、私は「viewOptions」アプローチでもっと運が良くなり、_configureメソッドをオーバーライドすることを望んでいます
できれば、これはすべて UI.Component またはその子で行われます。オプションなどを拡張するために、このライブラリのユーザーがヘッダー定義 (MyApp.Headers.Default = UI.Header.extend) に「ボイラープレート コード」を追加することは望ましくありません。
今、私はどういうわけか、すべての「子孫」からすべてのプロパティを組み合わせて取得する必要があります。どうすればいいのかまったくわかりません。バックボーンの舞台裏で何が起こっているのかを追ってみましたが、頭を包むことはできません。
したがって、これを行うためのヒント/コツは非常に高く評価されます。また、別の方法、または私の正確な要件と一致しない方法も大歓迎です。
編集1
「ある程度」機能するものがあるようです。これは次のようになります
インスタンスにオプションを追加するために、_configure メソッドをオーバーライドします。_.extend の最初の引数として this.getDefaultOptions() に注意してください。
UI.Component = Backbone.View.extend({
_configure: function(options) {
var viewOptions = this.viewOptions;
options = _.extend(this.getDefaultOptions ? this.getDefaultOptions() : {}, this.options || {}, options || {});
for (var i = 0, l = viewOptions.length; i < l; i++) {
var attr = viewOptions[i];
if (options[attr]) this[attr] = options[attr];
}
this.options = options;
}
});
この新しいメソッドをすべてのコンポーネントに追加しましたが、基本オブジェクト (UI.Component) に「共有」プロパティを配置しませんでした。うまく動作させることができなかったからです。
UI.Header = UI.Component.extend({
viewOptions: ['children', 'backButtonTitle', 'title'],
getDefaultOptions: function() {
return {
children: []
};
},
});
今、私はこのようなものを使ってヘッダーを定義しています
MyApp.Headers.Default = UI.Header.extend({
options: {
backButtonTitle: 'Terug',
titleBarChildren: [
new UI.SegmentedController({
children: [
new UI.Button('Lame example')
]
})
]
}
});
私はそれを現状のままにして、この「解決策」が存続するかどうかを確認し、報告します. もっと良い答えがあると思われる場合は、ためらわずに投稿してください =)
編集
これは私の最新のアプローチです。jQuery のディープ コピーを使用すると、問題なく動作するようです。
var UI = {};
var App = {
Headers: {}
};
UI.Component = Backbone.View.extend({
blockDefaults: {
children: []
},
initialize: function(options) {
var combinedDefaultsAndOptions = $.extend(true, {}, this.blockDefaults || {}, this.defaults || {}, this.options || {}, options || {});
_.defaults(this, combinedDefaultsAndOptions);
}
});
UI.Header = UI.Component.extend({
defaults: {
backButton: null,
backButtonTitle: null,
secondaryBarChildren: []
}
});
App.Headers.Default = UI.Header.extend({
options: {
backButtonTitle: "App back",
secondaryBarChildren: ["App child"]
}
});
var header1 = new UI.Header({
backButtonTitle: "Header 1 Back",
secondaryBarChildren: ["Header 1 child"]
});
var header2 = new UI.Header({
backButtonTitle: "Header 2 Back",
secondaryBarChildren: ["Header 2 child"]
});
var header3 = new App.Headers.Default({
});
var header4 = new App.Headers.Default({
backButtonTitle: "Overrided App Back"
});
header1.secondaryBarChildren.push('a child for header 1');
console.log(header1, header2, header3, header4);