45

ExtJS 4 でアプリをビルドするときに苦労しています。その一部は、いつ initComponent() で何かを構成するか、いつ構成しないかについて混乱しています...

たとえば、Sencha 自身のMVC アプリケーション アーキテクチャドキュメントでは、最初にグリッド ビューを作成するときに、initComponent() メソッドでインライン ストアを定義しました。(「ビューの定義」セクションを参照)

さらに下では、ストアを別のクラスに分解するときに、定義を initComponent() の外に移動しました。この事実に注意を引く有益なコメントがありますが、説明はありません。(モデルとストアの作成セクションを参照)

理由は明らかだと思いますが、見逃しています。ポインタはありますか?

4

4 に答える 4

44

ExtJSクラスシステムがどのように機能するかを深く理解していない場合は、次のことをお勧めします。

ですべての非プリミティブ型を宣言しますinitComponent()

用語

  • プリミティブ型-文字列、ブール値、整数など。
  • 非プリミティブ-配列とオブジェクト。

説明

拡張するコンポーネントを複数回作成する場合は、構成オプション(外部​​)として宣言された非プリミティブ構成がinitComponentすべてのインスタンス間で共有されます。

このため、拡張コンポーネント(通常は拡張グリッド)が複数のタブで作成されると、多くの人が問題を経験しました。

この動作は、以下のsraの回答と、このSkirtle'sDenの記事で説明されています。このSOの質問も読むことをお勧めします。

于 2013-01-24T02:08:57.200 に答える
14

私は通常、クラス構成オプションでできるだけ多くの構成を行うことを提唱します。これは、読みやすく、サブクラスでオーバーライドしやすいためです。それに加えて、将来、Sencha Cmd がコンパイラを最適化する可能性が高いため、コードを宣言型に保つと、最適化の恩恵を受ける可能性があります。

比較:

Ext.define('MyPanel', {
    extend: 'Ext.grid.Panel',

    initComponent: function() {
        this.callParent();
        this.store = new Ext.data.Store({
            fields: [ ... ],
            proxy: {
                type: 'direct',
                directFn: Direct.Store.getData
            }
        });
        this.foo = 'bar';
    }
});

...

var panel = new MyPanel();

と:

Ext.define('MyPanel', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.mypanel',

    foo: 'bar',

    store: {
        fields: [ ... ],
        proxy: {
            type: 'direct',
            directFn: 'Direct.Store.getData'
        }
    }
});

...

var panel = Ext.widget({
    xtype: 'mypanel',
    foo: 'baz'
});

これらのアプローチが非常に異なることに注意してください。最初の例では、オブジェクトのプロパティ値、ストア構成、使用時の MyPanel クラス名など、多くの部分をハードコーディングしています。クラスは拡張不可能になるため、クラスのアイデアを事実上殺しています。2 番目の例では、おそらく異なる構成で何度も再利用できるテンプレートを作成しています。基本的に、それがクラス システム全体の目的です。

しかし、実際の違いはもっと深いところにあります。最初のケースでは、実質的に実行時までクラス構成を延期していますが、2 番目のケースでは、クラス構成を定義し、それを非常に明確に異なる段階で適用しています。実際、2 番目のアプローチは、JavaScript にネイティブに欠けているもの、つまりコンパイル時のフェーズを導入していると簡単に言えます。また、フレームワークのコード自体で活用される多くの可能性を提供してくれます。いくつかの例が必要な場合はExt.app.ControllerExt.app.Application最新の 4.2 ベータ版をご覧ください。

より実用的な観点からは、2 番目のアプローチの方が読みやすく、扱いやすいため、より優れています。アイデアを理解すると、すべてのコードをそのように書いていることに気付くでしょう。この方法の方が簡単だからです。

このように考えてみてください: 古いスタイルの Web アプリケーションを作成し、サーバー側で HTML などを生成する場合、コードに HTML を混在させないようにしますよね? 左がテンプレート、右がコード。これは、データをハードコーディングするのと実質的に同じですinitComponent。確かに、ある程度までは機能します。その後、スパゲッティのボウルになり、維持と拡張が困難になります。ああ、それをすべてテストしてください!うん。

現在、クラス定義時とは対照的に、実行時にインスタンスで何かを行う必要がある場合があります。古典的な例は、イベントリスナーの適用、またはコントローラーの呼び出しです。オブジェクト インスタンスから実際の関数参照を取得する必要があり、それをまたはで行う必要があります。ただし、この問題の緩和に取り組んでいます。これらすべてをハードコーディングする必要はありません。すでに文字列リスナー名をサポートしており、MVC もまもなくサポートされます。controlinitComponentinitObservable.on()

上記のコメントで述べたように、ドキュメントの記事またはガイドを作成して説明する必要があります。おそらく、4.2 がリリースされるまで待つ必要があります。それまでの間、この回答が問題を明らかにするはずです。

于 2013-01-24T01:17:21.390 に答える
12

ここにたどり着いたとき、同じ質問に対する答えを探していましたが、これらの答えを見てがっかりしました。これらのどれも質問に答えません: initComponent() またはコンストラクター?

クラス構成オプション オブジェクトは共有されており、インスタンスごとに初期化/処理する必要がありますが、コードは initComponent() 関数と同様にコンストラクターにも入ることができます。

私の推測では、Component クラスのコンストラクターが途中で initComponent() を呼び出しており、私はそれほど間違っていませんでした。ソース コードを確認する必要がありましたが、実際にはAbstractComponent のコンストラクターです。

したがって、次のようになります。

AbstractComponent/ctor:
- stuffBeforeIC()
- initComponent()
- stuffAfterIC()

コンポーネントを拡張すると、次のようになります。

constructor: function () {
  yourStuffBefore();
  this.callParent(arguments);
  yourStuffAfter();
},
initComponent: function () {
  this.callParent();
  yourInitComp()
}

これらが呼び出される最終的な順序は次のとおりです。

- yourStuffBefore()
- base's ctor by callParent:
  - stuffBeforeIC()
  - initComponent:
    - base's initComponent by callParent
    - yourInitComp()
  - stuffAfterIC()
- yourStuffAfter()

したがって、最終的には、拡張するクラスのコンストラクターで検索できる stuffBeforeIC と stuffAfterIC の間にコードを挿入する必要があるかどうかによって異なります。

于 2013-05-01T11:29:16.730 に答える