extJSの初心者やチュートリアルの質がこれまでのところ多くのことを望まれているのは驚くべきことです。 ただし、標準のExtJS APIヘルプと同様に[1] 。
この記事の目的は、あなたのコードをサポートする人が自分の髪を引き裂くことを望まず、あなたが恥ずかしくないように、ExtJSベースのアプリケーションを書く方法を示すことです。 しかし、真剣に、この記事では、このフレームワークに関連してアプリケーションを設計および作成するためのシンプルで短いルールのセットを提供します。
DOM IDへの密結合を拒否する
ExtJSの例では、コンポーネントにidを厳密に指定する手法をよく使用します。その後、Ext.getCmp(id)呼び出しを介してクイック呼び出しが行われます。 「Hello world」レベルの例では、すべてが素晴らしく見えますが、プロジェクトがコードの代わりに大きくなるとすぐに混乱が現れます。
このアプローチの2番目の重要な欠点は、idがドキュメント全体(DOMツリー)内で一意でなければならないことです。
常にコンポーネントを分離および分離する
すべてが非常に簡単です。 標準コンポーネントのインスタンス化を継承に置き換えます。 この段階で、特定の境界線とテキストを含むソケットが表示されている場合でも、Ext.Panelを継承し、クラス自体でプロパティを定義します。
コードを「オブジェクトの宣言-コンテナに追加」という形式のシーケンスにしないでください。
つまり、次のようなコードは避けてください。
var p = new Ext.Panel({ region: 'north', height: 30, html: '<b>Test</b>' }); var mainPanel = new Ext.Panel({ layout: 'border', items: [ p, { region: 'center' title: 'Center' } ] });
そのようなコードはすぐに混乱に変わり、作成者でさえ理解できなくなります。 さらに、コード内のそのような要素間の依存関係の成長は、実際には制御されていません。
ネストされた構成オブジェクト:スコープを記憶する
JSの関数は、オブジェクトの代わりに呼び出すことができることを忘れないでください。 つまり、関数内の
this
は、一般的にどこでも話すことを示すことができます。 自分で関数を呼び出す場合、この状況を構文的に制御できます。 構成オブジェクトに異なるレベルのネストの関数(イベントハンドラー)が含まれる場合、スコープの問題はそれらに明白になります。 ほとんどの場合、
this
はハンドラーのロジックの一種の「参照ポイント」です。
this
失っ
this
-そして、それを非表示/無効にするなどのために次のボタンに到達する方法などは完全に理解できない
javascript言語は、少なくともFunctionオブジェクトのメソッドapply()およびcall() [2]を提供します。
ExtJSコアは、
createDelegate(scope)
メソッドでFunctionプロトタイプを補完します。 この関数は元の関数のラッパー関数を返すため、元の関数はスコープ内で呼び出されることが保証されます。
リスナーおよびExtJSイテレーターの場合、指定された関数を呼び出すスコープを明示的に設定できます[3] 。
ネストされたコンポーネントへのアクセス
ネストされたコンポーネントは、常に所有者のアイテムコレクションにあります。 子に到達するための少なくとも3つのオプションがあります。
- インデックスによるコレクションアイテムへのアクセス
- 非自明なコード; フォームの猛烈な構造は、this.get(0).get(3)を返すか、さらに悪い場合はthis.items.items [0] .items.items [3]を返します
- アイテム内のコンポーネントの順序が変更されました-すべてが壊れています
- ドキュメントのDOMで親を描画する前の項目は単なる配列です(以下を参照)。
- itemIdによるコレクションアイテムへのアクセス。 この識別子はdom idに関連付けられていませんが、要素の呼び出しをより意味のあるものにすることができます。 また、このメソッドは、コンポーネントが親で宣言される順序に依存しません。
- ref。 Refは、指定された要素へのリンクが作成されるときに呼び出される方法と、このリンクが配置されるレベルを指定する方法です。
refとitemIdの使用例は、次の例で見ることができます。
Ext.ns('Util'); Util.MyPanel = Ext.extend(Ext.Panel, { constructor: function (config) { config = config || {}; Ext.apply(config, { border: false, layout: 'card', activeItem: 0, items: [{ xtype: 'panel', itemId: 'mainScreen', layout: 'border', items: [{ //...skipped... } ] }, { xtype: 'editpanel', itemId: 'editScreen', listeners: { scope: this, cancel: this.showMainScreen, finish: this.onRuleSaved } } ], buttons: [{ ref: '../editBtn', handler: this.onEditBtn, scope: this }] } ); Util.MyPanel.superclass.constructor.call(this, config); }, showMainScreen: function () { this.getLayout().setActiveItem('mainScreen'); this.editBtn.enable(); }, showEditScreen: function () { this.getLayout().setActiveItem('editScreen'); }, //... other methods } ); Ext.reg('mypanel', Util.MyPanel);
独自のイベントを登録する
ExtJSのイベント-ウィジェットの相互作用の主なメカニズム。 これは、コンポーネントがその状態を外部に知らせる一種の方法です。 各ウィジェットは、他の人のイベントのリスナーであり、独自のソースになることもできます。 この場合、コンポーネントは任意の数のリスナーを持つことができ、それらすべてがイベントについて通知されます。 一般的に、学生に通知する手順は定義されていません。
イベントは、受信者とその数に関する最小限の仮定を意味し、コードの一貫性を大幅に低下させます。 これにより、コンポーネントがポータブルになり、他の組み合わせで再利用できるようになります。
コンポーネントに、外部のオブジェクトが知りたい状態がある場合、独自のイベントを登録します。
複合ウィジェットを作成していて、内部コンポーネントが外部に何かを伝える必要がある場合-独自のイベントを使用します。
レンダリングの前後のオブジェクト。 アフターレンダーが必要な場合
各ビジュアルコンポーネントは、ブラウザページのDOM要素に基づいています。 同時に、コンポーネントには、オブジェクトとして既に作成されているが、DOMツリーにまだ「描画」されていない状態があります。 この状態では、内部DOM構造へのアクセスは不可能です。 この状態のオブジェクトは半機能的です。正式には、宣言されたすべてのメソッドがありますが、それらが正しく機能するという保証はありません。
コンポーネントは、DOM構造内で自身を修正するとすぐに、renderイベントを生成してから、afterrenderを生成します。 正直なところ、これらのイベント間に特別な違いはありませんが、一般的にレンダーイベントは内部の目的でコンポーネントによって使用され、独自のメソッド、たとえばonRender()を呼び出して、そのようなイベントのプロセッサを誤ってブロックする可能性が高くなります このような明白でない問題をキャッチするのはそれほど簡単ではなく、ExtJSは、ご存じのように、常に沈黙の中で「落ちます」。
コンポーネントは、子コンポーネントがレンダリングされる前に既にレンダリングされていることを報告することに注意してください。
DOM要素の存在を必要とするコンポーネントへの呼び出しを正しく処理することをお勧めします。 この場合、コンポーネントがレンダリングされない場合、これらの操作はレンダリングされるまで「延期」する必要があります。この場合、ハンドラーを単にアフターレンダーに動的にハングさせます。
以下は、コンポーネントがDOMにレンダリングされる前に呼び出しが発生した場合に、状況を正しく処理する関数の例です。
//...other property definitions... showDocFeedOptions: function (show) { var fn = function () { this.feedDocsFieldSet.setVisible(!!show); }; if (this.rendered) { fn.apply(this); } else { this.on('afterrender', fn, this); } }
遅延初期化。 Xtype
xtype構成オブジェクトのマジックプロパティ(別の「トリック」)は、構築されるオブジェクトのタイプを一意に決定します。 つまり、このような構成オブジェクトをExt.ComponentMgr.create()ユニバーサルファクトリーに渡すと(ネストされた構成オブジェクトごとに自動的に呼び出されます)、対応するクラスのインスタンスが出力で取得されます。
このアプローチにより、次のことが可能になります。
- ウィジェット構造が表示されるネストされた構成オブジェクトを作成する
- 手動でオブジェクトを作成し、それらをコンテナに追加するシーケンスを遅らせる
- 必要に応じてコンポーネントを作成します(これにより、アプリケーションのレンダリング速度が向上します)
結論の代わりに-設計について少し
原則として、実際には、かなり複雑なコントロールとコンポーネントを処理する必要があります。 この意味で、単純なコンポーネントまたは複合コンポーネントである論理ブロック(ウィジェット)に分割すると便利です。 複合ウィジェットの要素間の構造と制御転送スキームを検討することは非常に重要です。 私の練習では、次のアプローチを使用します。
- 外部コンポーネント(「親」と呼びましょう)は、ネストされた(子)要素について知っています。 その逆は真実ではありません。
- 親は子に直接アクセスできます。
- 子要素は、イベントのメカニズムを通じてのみ情報を「上」に報告します。 子は、親とそのメソッドのセットについて何も仮定しないでください。
- 子供同士の「水平な」関係(互いに直接電話をかけること)は厳しく禁止されています。 親だけが「娘」の同期に従事しています。
- 定数のDOM ID(Ext.getCmp())を介した呼び出しは厳しく禁止されています。