6

これは 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);
4

1 に答える 1

1

あなたの例の初期化関数をオーバーライドしたいと思いますが、多くのことが起こっているのでわかりません。これがオフの場合はご容赦ください。そして、私はあなたがやろうとしていると私が思うことを、より「バックボーン」スタイルのシステムに整理しているだけかもしれません.

次のような基本コンポーネントから始めます。

UI.Component = Backbone.View.extend({
    defaults : { 'children' : [] },
    initialize : function (options) {
        _.defaults(options, this.defaults);
        _.keys(this.defaults).forEach(function(key) {
              this[key] = this.options[key];
        }.bind(this));
        Backbone.View.prototype.initialize.call(this, options);
    },
    add: function(child) {
        this.children.push(child);
    }
});

次に、次のように同様の方法でそれらを拡張し続けることができます。

UI.Header = UI.Component.extend({
    defaults : { 
        'titleBarChildren' : [], 
        'secondaryBarChildren' : [], 
        'title' : '', 
        'backButtonTitle' : 'Back' 
    },
    initialize : function (options) {
        _.defaults(options, this.defaults);
        _.keys(this.defaults).forEach(function(key) {
              this[key] = this.options[key];
        }.bind(this));
        UI.Component.prototype.initialize.call(this, options);
    }
});

コードでやろうとしていることの内訳は次のとおりです。

デフォルトは、すべてのデフォルト属性をきれいに保持するオブジェクトを作成します

    defaults : { 'children' : [] },

初期化オーバーライドを使用すると、ビューからビューへオプションを渡し続けることができますが、各コンポーネントはdefaultsオブジェクトを使用してギャップを埋めます。

    initialize : function (options) {
        // merges your defaults in with the options passed
        _.defaults(options, this.defaults);
        // loop through your required defaults for this view
        // assigning the attributes to the passed options
        _.keys(this.defaults).forEach(function(key) {
              this[key] = this.options[key];
        }.bind(this));
        // Finally pass all your options up the chain of inheritance
        UI.Component.prototype.initialize.call(this, options);
    },
于 2012-12-18T21:01:30.877 に答える