コントローラーについて
ExtJS 4では、コントローラーは
Ext.app.Controller
から継承されたクラス
Ext.app.Controller
。 これらのコントローラーは、CSSのようなセレクター(「コンポーネントクエリ」と呼ばれる)を使用して、コンポーネントとそのイベントハンドラーをマッピングします。 また、いわゆる
refs
を使用して、コンポーネントのインスタンスをフェッチおよび取得します。
これらのコントローラーは、アプリケーションの起動時に作成され、ライフサイクル全体で機能します。 ビューは作成および削除され、複数のインスタンスが存在する場合があり、コントローラーは全員にサービスを提供します。
難しさ
大規模なアプリケーションの場合、これらの手法にはいくつかの困難が伴います。
そのような場合、リプレゼンテーションとコントローラーは、異なる開発チームの異なる作成者が作成し、最終アプリケーションに統合できます。 また、コントローラーが意図されたアイデアにのみ反応することを確認することは、すでに困難です。 また、開発者は通常、アプリケーションの起動時に作成されるコントローラーの数を減らしたいと考えています。 また、コントローラーを作成する機会(多少の努力を払って)が延期されるため、コントローラーを削除する可能性がないため、コントローラーが不要になった場合でも残ります。
ViewControllers
Ext JS 5は現在のコントローラーと下位互換性があることを考慮して、このような問題を解決するために設計された新しいタイプのコントローラー
Ext.app.ViewController
ます。 ソリューションは次のように実現されます。
-
listeners
とreference
の構成プロパティreference
、ビューとの通信が簡素化されます。 - ビューのライフサイクルは、対応するViewControllerを自動的に制御するために使用されます。
- ViewControllersの複雑さは次のように軽減されます。 1対1の関係は、対応する表現で使用されます。
- カプセル化は、ネストされたビューを作成するために提供されています。
- コンポーネントを選択し、対応するビューの下の任意のレベルでイベントを追跡することは引き続き可能です。
リスナー
listeners
新しいもので
listeners
ませんが、Ext JS 5では新しい機能が追加されました。 新しいリスナーのより完全な議論は、今後の記事「Ext JS 5の宣言的リスナー」にあります。 ViewControllersで使用するために、いくつかの例を見ることができます。 1つ目は、ネストされたビューコンポーネントでの
listeners
構成の通常の使用です。
Ext.define('MyApp.view.foo.Foo', { extend: 'Ext.panel.Panel', xtype: 'foo', controller: 'foo', items: [{ xtype: 'textfield', fieldLabel: 'Bar', listeners: { change: 'onBarChange' // (scope) } }] }); Ext.define('MyApp.view.foo.FooController', { extend: 'Ext.app.ViewController', alias: 'controller.foo', onBarChange: function (barTextField) { // 'change' } });
この場合、
onBarChange
名前付きハンドラーに
onBarChange
特定の
scope
があり
onBarChange
ん。
Bar
テキストフィールドのイベントシステム自体が、独自のViewControllerをデフォルトコンテキストにします。
歴史的に、
listeners
設定は親コンポーネントで使用するために予約されていました。そのため、ビューは独自のイベントや基本クラスによって呼び出されたイベントをどのようにリッスンできますか? 答えは、明示的なコンテキストを使用することです。
Ext.define('MyApp.view.foo.Foo', { extend: 'Ext.panel.Panel', xtype: 'foo', controller: 'foo', listeners: { collapse: 'onCollapse', scope: 'controller' }, items: [{ ... }] });
この例では、ExtJS 5の2つの新機能、 名前付きスコープと宣言リスナー(約Transl。 )を使用します。 名前付きコンテキストに焦点を当てます。 名前付きコンテキストの場合、
"this"
と
"controller"
2つの名前が有効です。 MVCアプリケーションを作成するときは、ほとんど常に
"controller"
使用します。これは明らかに、独自のViewControllerになります(階層の上位にあるビューのViewControllerではありません)。
なぜなら ビューは
Ext.Component
である
Ext.Component
このビューに
xtype
を割り当てました。これにより、
textfield
行ったのと同じ方法で他のビューでインスタンス化できます。 すべてがどのように組み合わされるかを確認するには、階層を作成します。
Ext.define('MyApp.view.bar.Bar', { extend: 'Ext.panel.Panel', xtype: 'bar', controller: 'bar', items: [{ xtype: 'foo', listeners: { collapse: 'onCollapse' } }] });
この場合、
Bar
ビューは要素の1つとして
Foo
インスタンスを作成します。 次に、
Foo
ビューと同じ方法で
collapse
イベントをリッスンします。 Ext JSおよびSencha Touchの以前のバージョンでは、これらの定義は矛盾していました。 ただし、これはExt JS 5で解決されます。Fooで宣言されたリスナーは、ViewController
Foo
で動作し、
Bar
で宣言されます-ViewController
Bar
。
参照資料
コントローラロジックで広く使用されている機能の1つは、アクションを実行するために必要なコンポーネントを取得することです。 このようなもの:
Ext.define('MyApp.view.foo.Foo', { extend: 'Ext.panel.Panel', xtype: 'foo', controller: 'foo', tbar: [{ xtype: 'button', text: 'Add', handler: 'onAdd' }], items: [{ xtype: 'grid', ... }] }); Ext.define('MyApp.view.foo.FooController', { extend: 'Ext.app.ViewController', alias: 'controller.foo', onAdd: function () { // ... grid ... } });
しかし、どのようにしてテーブル(ガード)を取得しますか? ExtJS 4では、構成
refs
またはその他の方法を使用してコンポーネントを取得できます。 すべての手法では、テーブルを一意に識別するために、認識可能なプロパティをテーブルに指定する必要があります。 古い技術者は、
id
(および
Ext.getCmp
)
Ext.getCmp
または
itemId
(
refs
または別の選択方法を使用)を使用していました。
id
の利点はクイックフェッチですが、 識別子はアプリケーション全体およびDOM内で一意である必要がありますが、これは常に達成できるとは限りません。
itemId
とさまざまな種類のクエリ(クエリ)を使用するとより柔軟になりますが、適切なコンポーネントを見つけるには検索する必要があります。
Ext JS 5の新しい
reference
では、単にテーブルに追加し、
lookupReference
を使用して取得します。
Ext.define('MyApp.view.foo.Foo', { extend: 'Ext.panel.Panel', xtype: 'foo', controller: 'foo', tbar: [{ xtype: 'button', text: 'Add', handler: 'onAdd' }], items: [{ xtype: 'grid', reference: 'fooGrid' ... }] }); Ext.define('MyApp.view.foo.FooController', { extend: 'Ext.app.ViewController', alias: 'controller.foo', onAdd: function () { var grid = this.lookupReference('fooGrid'); } });
これは、
itemId = 'fooGrid'
を割り当ててから
this.down('#fooGrid')
を割り当てることに似ています。 しかし、「フードの下」では、違いは重要です。 まず、
reference
構成では、コンポーネントが所有者ビューに登録する必要があります。 第二に、
lookupReference
メソッドはキャッシュに更新の必要性を尋ねます(コンテナの追加または削除によるものと仮定します)。 すべてが正常であれば、キャッシュからリンクを返すだけです。 擬似コードで:
lookupReference: (reference) { var cache = this.references; if (!cache) { Ext.fixReferences(); // cache = this.references; // } return cache[reference]; }
つまり、検索は行われず、コンテナに要素を追加または削除することによって破損した接続は、必要なときに即座に修正されます。 以下で見るように、効率に加えて、このアプローチには他の利点もあります。
カプセル化
Ext JS 4 MVC実装でセレクターを使用することは非常に柔軟でしたが、同時にいくつかのリスクも伴いました。 セレクターがすべてのレベルのすべてのイベントを「見た」という事実は強力でしたが、エラーが発生しがちでした。 たとえば、100%エラーなしで単独で動作するコントローラーは、望ましくない一致するセレクターを持つ新しいビューが表示されるとすぐにエラーを作成する可能性があります。
これはいくつかのプラクティスに従うことで解決できますが、ViewControllerでリスナーとリンクを使用すると、これらの問題は単純に解消されます。 そしてすべては、
reference
と
listeners
構成がViewControllerでのみビューを接続するためです。 ネストされたビューは、現在のビュー内の任意の
reference
値を使用できます。これらの名前は、上位の階層ビューに対して開かれないことを知っています。
同時に、
listeners
対応するViewControllerから要求され、誤ったセレクターを持つ他のコントローラーで処理することはできません。 リスナーがセレクタよりも望ましいことを考えると、これら2つのメカニズムは、セレクタベースのアプローチの使用が正当化される場所で同時に機能します。
この例を完了するために、ビューが上位レベルのビューのViewControllerによって処理されるイベントを発生させる場合を考えてください。 これを行うために、ViewControllerにはヘルパーメソッド
fireViewEvent
ます。 例:
Ext.define('MyApp.view.foo.Foo', { extend: 'Ext.panel.Panel', xtype: 'foo', controller: 'foo', tbar: [{ xtype: 'button', text: 'Add', handler: 'onAdd' }], items: [{ xtype: 'grid', reference: 'fooGrid' ... }] }); Ext.define('MyApp.view.foo.FooController', { extend: 'Ext.app.ViewController', alias: 'controller.foo', onAdd: function () { var record = new MyApp.model.Thing(); var grid = this.lookupReference('fooGrid'); grid.store.add(record); this.fireViewEvent('addrecord', this, record); } });
これにより、階層の上位のビューで標準リスナーを使用できるようになります。
Ext.define('MyApp.view.bar.Bar', { extend: 'Ext.panel.Panel', xtype: 'bar', controller: 'bar', items: [{ xtype: 'foo', listeners: { collapse: 'onCollapse', addrecord: 'onAddRecord' } }] });
fireViewEvent
から:
fireViewEvent
にくいですが、本質的に
fireViewEvent
使用
fireViewEvent
と、ViewController内のビューのイベントを発生させることができ
fireViewEvent
。 つまり、この場合、ViewControllersがない場合、これは「Foo」ビューコードで通常の
fireEvent
を呼び出すことに
fireEvent
します。
リスナーとイベントドメイン
Ext JS 4.2では、MVCイベントマネージャーにイベントドメインが導入されました。 これらのドメインは、呼び出されるとすぐにイベントをインターセプトし、セレクターの一致によってそれらを処理するコントローラーに渡します。
component
イベントドメインはコンポーネントセレクターを完全にサポートしていますが、他のものはサポートが制限されています。
Ext JS 5では、各ViewControllerは
view
と呼ばれる新しいタイプのイベントドメインのインスタンスを作成します。 このイベントドメインにより、ViewControllersは標準の
listen
および
control
メソッドを使用できますが、暗黙的にスコープを独自のビューに制限します。 また、彼は自分の見解に一致する新しい特別なセレクターを追加します。
Ext.define('MyApp.view.foo.FooController', { extend: 'Ext.app.ViewController', alias: 'controller.foo', control: { '#': { // collapse: 'onCollapse' }, button: { click: 'onAnyButtonClick' } } });
リスナーとセレクターの主な違いは、次の例で見ることができます。
button
セレクターは、このビューまたは任意のサブボタンの任意のボタンに一致しますが、少なくともサブサブサブでは重要ではありません。 つまり、セレクタベースのハンドラーは継承境界を考慮しません。 この動作は、以前の
Ext.app.Controller
動作と一貫性があり、状況によっては便利なテクニックかもしれません。
最後に、これらのドメインは、ネストを考慮して、イベントを表現の階層に効率的に転送します( イベントをバブルアップ-約Transl。 )。 つまり、イベントがトリガーされると、最初に標準リスナーに渡されます。 次に、所有者のViewControllerに渡され、次に階層を上って親のViewController(存在する場合)に渡されます。 最終的に、イベントは
Ext.app.Controller
コントローラーで処理するために標準
component
イベントドメインに
Ext.app.Controller
れます。
ライフサイクル
大規模アプリケーションの標準的なプラクティスは、必要に応じてコントローラーを動的に作成することです。 これにより、アプリケーションのロード時間を短縮し、他のコントローラーに影響を与えることなくパフォーマンスを向上させることができます。 以前のバージョンでのこのアプローチの制限は、作成されたとき、これらのコントローラーがアプリケーションの寿命を通して機能し続けることでした。 それらを破壊してリソースを解放することは不可能でした。 また、コントローラーがビューの複数のインスタンスを提供でき、単一のインスタンスを提供できるという意味で、何も変わっていません。
したがって、ビューのライフサイクルでは、ViewControllerがすぐに作成され、そのビュー全体にわたってこのビューにアタッチされます。 ビューが削除されると、ViewControllerも削除されます。 これは、ViewControllerがビューがないかいくつかの場合に動作する必要がなくなったことを意味します(ビューがないか、多くのビューがある状態を管理することを強制されなくなりました-明らかに、古典的なコントローラーとの比較があります;およそTransl 。
1対1の関係により、リンクトラッキングが簡素化され、リモートコンポーネントの漏洩が不可能になります。 ViewControllerライフサイクルで次の主要なイベントが発生します。
- beforeInitは、initComponentメソッドを呼び出す前にプレゼンテーションを制御するためにオーバーライドできるメソッドです。 コンポーネント
initConfig
またはそのコンストラクターがinitConfig
ときに、コントローラーが作成された直後に呼び出さinitConfig
ます。 - init -
initComponent
メソッドがinitComponent
完了した直後に呼び出されinitComponent
。 これは、プレゼンテーションが既に初期化されているコントローラーを初期化するための典型的なポイントです。 - initViewModel-ビューのViewModelが作成されたときに呼び出されます(定義されている場合)。
-
callParent
リソースのクリーンアップ(callParent
呼び出しを忘れないでください)。
おわりに
ViewControllersは、アプリケーションのアップグレードに優れていると思います。 また、ViewModelsとうまく機能するため、両方のアプローチの長所を組み合わせることができます。 今後のリリースに満足しており、アプリケーションの改善も歓迎します。
PS
前の投稿: Ext JS 5:MVC、MVVMなど