ExtJS 5でViewControllerを使用する

ExtJS 5はいくつかのエキサイティングなアーキテクチャの改善をもたらします。MVCアプリケーションを強化するために、ViewModel、MVVM、およびViewControllerのサポートを追加しました。 最良の部分は、これらの関数が相互に排他的ではないため、段階的に入力するか、同時に使用できることです。





コントローラーについて



ExtJS 4では、コントローラーはExt.app.Controller



から継承されたクラスExt.app.Controller



。 これらのコントローラーは、CSSのようなセレクター(「コンポーネントクエリ」と呼ばれる)を使用して、コンポーネントとそのイベントハンドラーをマッピングします。 また、いわゆるrefs



を使用して、コンポーネントのインスタンスをフェッチおよび取得します。



これらのコントローラーは、アプリケーションの起動時に作成され、ライフサイクル全体で機能します。 ビューは作成および削除され、複数のインスタンスが存在する場合があり、コントローラーは全員にサービスを提供します。



難しさ


大規模なアプリケーションの場合、これらの手法にはいくつかの困難が伴います。



そのような場合、リプレゼンテーションとコントローラーは、異なる開発チームの異なる作成者が作成し、最終アプリケーションに統合できます。 また、コントローラーが意図されたアイデアにのみ反応することを確認することは、すでに困難です。 また、開発者は通常、アプリケーションの起動時に作成されるコントローラーの数を減らしたいと考えています。 また、コントローラーを作成する機会(多少の努力を払って)が延期されるため、コントローラーを削除する可能性がないため、コントローラーが不要になった場合でも残ります。



ViewControllers



Ext JS 5は現在のコントローラーと下位互換性があることを考慮して、このような問題を解決するために設計された新しいタイプのコントローラーExt.app.ViewController



ます。 ソリューションは次のように実現されます。





リスナー


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ライフサイクルで次の主要なイベントが発生します。







おわりに



ViewControllersは、アプリケーションのアップグレードに優れていると思います。 また、ViewModelsとうまく機能するため、両方のアプローチの長所を組み合わせることができます。 今後のリリースに満足しており、アプリケーションの改善も歓迎します。



PS


前の投稿: Ext JS 5:MVC、MVVMなど



All Articles