Ext UIコントロールの作成を教えます


ExtJsを使用した新しいUIコントロールの作成
このドキュメントでは、ExtJS 2について説明します.xのライブラリでは,既存のクラスの能力を新しいユーザインタフェースコントロールに拡張する.閣下がこの文について議論したいなら、フォーラムの投稿に行ってください.
組み合わせまたは拡張
新しいクラスを作成すると、ツールクラスのインスタンスを持って最も重要な役割を果たすか、そのクラスを拡張するかの選択が行われます.
ExtJsを使用する場合は、最も近いベースクラスから拡張し、必要な機能を実現することをお勧めします.これは、Extが提供する自動生存サイクルが、自動レンダリングのメカニズムを導入し、レイアウトマネージャからのUIコンポーネントのレイアウト制御を自動的に調整し、コンテナで自動的に破棄する機能を担うためである.
新しいクラスを組織して、それはExtJsのクラスで、実現するのはとても便利で、これはContainer→Component階層の形成を招いて、比較して、新しいクラスはExtJsクラスを持っているならば、周辺からそれに対してレンダリングして組織しなければなりません.
The Template method Patternテンプレートメソッドモード
Ext JsのComponentの継承階層は、Template Method pattern(テンプレートメソッドモード)を使用してサブクラスに委任され、サブクラスに渡されて特定の動作を担当します.
継承チェーン内の各サブクラスは、コンポーネントのライフサイクルのある段階で「コミット(contribute)」の追加の論理機能を持つことができます.これにより、各クラスは独自の動作を持ち、他のクラスは独自の動作を加えても相互に影響を与えません.
一例はレンダー(レンダリング)レンダーれんだりんぐ関数である.render関数は上書きできません.各サブクラスの実装にonRenderメソッドを階層的に追加すると、render関数は実行時に各onRenderメソッドを呼び出しにアクセスします.各onRenderメソッドは、親クラスのonRenderメソッドを呼び出してから、自分(サブクラス)の論理部分を「没頭処理(contribute)」する必要があります.
テンプレートメソッドonRendererの機能手順を以下の例で示した.
renderはコンテナのレイアウトマネージャ(Container’s layout manager)によって呼び出されます.このメソッドのインプリメンテーションはExtベースクラスによって提供される「消去(overridden)」できません.this.onRenderは現在のサブクラスに書かれているインプリメンテーションを表します.(指定されている場合).親のバージョン、親のバージョンにアクセスし、親、親のバージョンを呼び出します.最終的には、各クラスがその機能を完了し、render関数の戻り値が生存サイクルを制御します.
 
ExtJSコンポーネント(Component)の生存期間において、クラス固有の論理機能を実現するためのいくつかの有意義なテンプレートアプローチが提供される.
強調:サブクラスを記述する場合、テンプレートメソッドはインスタンス化の過程で呼び出され、生存周期の一部に属する動作であり、イベントの一部ではない.イベントはhandlerによって保留されたり、中止されたりする可能性があります.
次は、Componentサブクラスが使用できるテンプレートメソッドです.
  • onRender

  • レンダリング中に特定の動作を追加できます.親のonnderが呼び出されると、コンポーネントのElement要素を決定できます.このフェーズでは、構造上の制御(HTML構造)を完了するために、残りのDOMタスクを実行できます.
  • afterRender

  • レンダリングが完了したら、特定の動作を追加できます.このフェーズのコンポーネント要素は、コンフィギュレーションの要件に従ってスタイルを設定し、コンフィギュレーションされたCSSスタイル名で指定されたスタイル名が導入され、可視性(visibility)とコンフィギュレーションアクティブ化(enable)が構成されます.
  • onShow

  • コンポーネントを表示しながら特定の動作を追加できます.親のonShowが実行されると、Componentnetが表示されます.
  • onHide

  • コンポーネントを非表示にしながら、特定の動作を追加できます.親のonHideが実行されると、Componentnetは非表示になります.
  • onDisable

  • コンポーネントを無効にしながら、特定の動作を追加できます.親のonDisableが実行されると、Componentnetは無効になります.
  • onEnable

  • コンポーネントをアクティブにしながら、特定の動作を追加できます.親のonEnableが実行されると、Componenetがアクティブになります.
  • onDestroy

  • コンポーネントを破棄しながら特定の動作を追加できます.親のonDestroyが実行されると、Componenetは破棄されます.
    Extコンポーネントクラスの各階層には、独自のテンプレートメソッドがあります.これらは、独自のニーズに基づいて設計されています.
    ヒント:親のテンプレートメソッドを呼び出す場合、最も簡潔な方法はFunctionを使用することです.applyは、すべてのパラメータが受け入れられることを保証し、そのテンプレートメソッドに送信します.
    Ext.ux.Subclass.superclass.onRender.apply(this, arguments);

    どのクラスを拡張するか
    適切なクラスを選択して拡張するには、ベースクラスがどのような機能を提供するかだけでなく、パフォーマンスにも重点を置く必要があります.複数のUIコントロールがレンダリングされても制御されても、Ext.Panelは派生オブジェクトであることが多い.
    Panelクラスには多くの能力があります.
  • Border(胴)
  • Header(ヘッド)
  • Headerツールバー
  • Footer(ボトム)
  • Footerボタン
  • Top toolbar(トップツールバー)
  • Bottom toolbar(ボトムツールバー)
  • サブアセンブリ
  • の受託および管理
    これらが役に立たない場合は、Panelを使うのは資源の浪費です.
    Component(コンポーネントクラス)
    要求されるUIコントロールが他の詳細なコントロールを必要としない場合、すなわち、HTML要素の一部をカプセル化するだけであれば、望ましい拡張オブジェクトはExt.BoxComponentまたはExt.Componentである.もう少し狭くすれば、親コンテナが提供するサイズコントロール機能に従う必要はありません.Ext.Componentを使用すればいいです.
    強調:Componentクラスはholderとしてどの要素が含まれているかを内省することはありません.したがって、必要な要素(Element)を作成するには、autoElの構成項目を設定する必要があります.
    たとえば、画像をComponentにカプセル化するには、次のように定義します.
    Ext.ux.Image = Ext.extend(Ext.Component, {
        autoEl: {
            tag: 'img',
            src: Ext.BLANK_IMAGE_URL,
            cls: 'tng-managed-image'
        },
     
    // Add our custom processing to the onRender phase.
    // We add a ‘load’ listener to our element.
        onRender: function() {
            Ext.ux.Image.superclass.onRender.apply(this, arguments);
            this.el.on('load', this.onLoad, this);
        },
     
        onLoad: function() {
            this.fireEvent('load', this);
        },
     
        setSrc: function(src) {
            this.el.dom.src = src;
        }
    });

    これは、非箱寸法モデル(non box-sizing)のレイアウトに参加できる、画像をカプセル化できるExt Componentクラスです.
    BoxComponent
    要求されるUIコントロールが他の詳細なコントロールを必要としない場合、つまり、HTML要素の一部をカプセル化するだけで、レイアウトマネージャが提供するサイズ、レイアウトのコントロールに従う場合、この拡張オブジェクトはExt.Boxです.
    たとえば、Loggerクラスがlog情報を簡単に表示しようとすると、layout:'fit'フォームに挿入するなど、レイアウトのスタイルを埋め込む必要があります.
    Ext.ux.Logger = Ext.extend(Ext.BoxComponent, {
        tpl: new Ext.Template("<li class='x-log-entry x-log-{0:lowercase}-entry'>",
            "<div class='x-log-level'>",
                "{0:capitalize}",
            "</div>",
            "<span class='x-log-time'>",
                "{2:date('H:i:s.u')}",
            "</span>",
            "<span class='x-log-message'>",
                "{1}",
            "</span>",
        "</li>"),
     
        autoEl: {
            tag: 'ul',
            cls: 'x-logger'
        },
     
        onRender: function() {
            Ext.ux.Logger.superclass.onRender.apply(this, arguments);
            this.contextMenu = new Ext.menu.Menu({
                items: [new Ext.menu.CheckItem({
                    id: 'debug',
                    text: 'Debug',
                    checkHandler: Ext.ux.Logger.prototype.onMenuCheck,
                    scope: this
                }), new Ext.menu.CheckItem({
                    id: 'info',
                    text: 'Info',
                    checkHandler: Ext.ux.Logger.prototype.onMenuCheck,
                    scope: this
                }), new Ext.menu.CheckItem({
                    id: 'warning',
                    text: 'Warning',
                    checkHandler: Ext.ux.Logger.prototype.onMenuCheck,
                    scope: this
                }), new Ext.menu.CheckItem({
                    id: 'error',
                    text: 'Error',
                    checkHandler: Ext.ux.Logger.prototype.onMenuCheck,
                    scope: this
                })]
            });
            this.el.on('contextmenu', this.onContextMenu, this, {stopEvent: true});
        },
     
        onContextMenu: function(e) {
            this.contextMenu.logger = this;
            this.contextMenu.showAt(e.getXY());
        },
     
        onMenuCheck: function(checkItem, state) {
            var logger = checkItem.parentMenu.logger;
            var cls = 'x-log-show-' + checkItem.id;
            if (state) {
                logger.el.addClass(cls);
            } else {
                logger.el.removeClass(cls);
            }
        },
     
        debug: function(msg) {
            this.tpl.insertFirst(this.el, ['debug', msg, new Date()]);
            this.el.scrollTo("top", 0, true);
        },
     
        info: function(msg) {
            this.tpl.insertFirst(this.el, ['info', msg, new Date()]);
            this.el.scrollTo("top", 0, true);
        },
     
        warning: function(msg) {
            this.tpl.insertFirst(this.el, ['warning', msg, new Date()]);
            this.el.scrollTo("top", 0, true);
        },
     
        error: function(msg) {
            this.tpl.insertFirst(this.el, ['error', msg, new Date()]);
            this.el.scrollTo("top", 0, true);
        }
    });

    続いてCSS:
    .x-logger {
        overflow: auto;
    }
    .x-log-entry .x-log-level {
        float: left;
        width: 4em;
        text-align: center;
        margin-right: 3px;
    }
    .x-log-entry .x-log-time {
        margin-right: 3px;
    }
    .x-log-entry .x-log-message {
        margin-right: 3px;
    }
    .x-log-debug-entry, .x-log-info-entry, .x-log-warning-entry, .x-log-error-entry {
        display: none;
    }
     
    .x-log-show-debug .x-log-debug-entry { display: block }
    .x-log-show-info .x-log-info-entry { display: block }
    .x-log-show-warning .x-log-warning-entry { display: block }
    .x-log-show-error .x-log-error-entry { display: block }
     
    .x-log-debug-entry .x-log-level { background-color: #46c }
    .x-log-info-entry .x-log-level  { background-color: green }
    .x-log-warning-entry .x-log-level  { background-color: yellow }
    .x-log-error-entry .x-log-level  { background-color: red }

    logの情報のHTMLリストはすべて1つのレイアウトに配置します.右クリックメニューがCSSスタイルクラスの名前に基づいてloggedエントリの可視性を操作できるように、onRenderのフェーズに処理を追加しました.この階層にあるオブジェクトには、特別なテンプレートメソッドも用意されています.
  • onResize

  • この時点で、Box Componentのサイズが変更され、残りのタスクが実行されます.
  • onPosition

  • この時点で、BoxComponentの位置が変更され、残りのタスクが実行されます.
    Container(コンテナクラス)
    必要なUIコントロールがベアラに使用される場合(Contain)他のUI要素はその身にあるが、前述したExt.Panelのような多くの機能を必要とせず、肥大化を避けるためにExt.Containerコンテナクラスを用いて継承すべきである.同様に、autoElで指定された要素の構成項目も少なくなく、ある要素の上でコンテナをレンダリングするために使用される.同様に、視覚制御においてスクロールバーが表示されるかどうかの面で(すなわちoverflowプロパティ)では、ユーザーはStyleコンフィギュレーションアイテム、またはコンテナ要素のclassプロパティの2つの方法でCSSスタイルを作成できます.
    注:Container階層では、サブコンポーネントをレンダリングおよびコントロールするために使用されるレイアウトクラスを忘れないでください.
    例のクラスは、条件コマンドのクエリーをカプセル化し、Storeのテストフィールドに基づくデータをフィルタできます.機能的なパッケージに加えて、クエリー・タスクを統一的にレイアウトし、制御可能なクラスにカプセル化することで、コンテナからクエリーのエントリを自動的に追加または削除しやすくなり、柔軟性が向上します.
    Ext.ux.FilterCondition = Ext.extend(Ext.Container, {
        layout: 'table',
     
        layoutConfig: {
            columns: 7
        },
     
        autoEl: {
            cls: 'x-filter-condition'
        },
     
        Field: Ext.data.Record.create(['name', 'type']),
     
        initComponent: function() {
            this.fields = this.store.reader.recordType.prototype.fields;
            this.fieldStore = new Ext.data.Store();
     
    // Create a Store containing the field names and types
    // in the passed Store.
            this.fields.each(function(f) {
                this.fieldStore.add(new this.Field(f))
            }, this);
     
    // Create a Combo which allows selection of a field
            this.fieldCombo = new Ext.form.ComboBox({
                triggerAction: 'all',
                store: this.fieldStore,
                valueField: 'name',
                displayField: 'name',
                editable: false,
                forceSelection: true,
                mode: 'local',
                listeners: {
                    select: this.onFieldSelect,
                    scope: this
                }
            });
     
    // Create a Combo which allows selection of a test
            this.testCombo = new Ext.form.ComboBox({
                triggerAction: 'all',
                store: ['<', '<=', '=', '!=', '>=', '>']
            });
     
    // Inputs for each type of field. Hidden and shown as necessary
            this.booleanInput = new Ext.form.Checkbox({
                hideParent: true,
                hidden: true
            });
            this.intInput = new Ext.form.NumberField({
                allowDecimals: false,
                hideParent: true,
                hidden: true
            });
            this.floatInput = new Ext.form.NumberField({
                hideParent: true,
                hidden: true
            });
            this.textInput = new Ext.form.TextField({
                hideParent: true,
                hidden: true
            });
            this.dateInput = new Ext.form.DateField({
                hideParent: true,
                hidden: true
            });
     
            this.items = [ this.fieldCombo, this.testCombo, this.booleanInput, this.intInput, this.floatInput, this.textInput, this.dateInput];
            Ext.ux.FilterCondition.superclass.initComponent.apply(this, arguments);
        },
     
        onFieldSelect: function(combo, rec, index) {
            this.booleanInput.hide();
            this.intInput.hide();
            this.floatInput.hide();
            this.textInput.hide();
            this.dateInput.hide();
            var t = rec.get('type');
            if (t == 'boolean') {
                this.booleanInput.show();
                this.valueInput = this.booleanInput;
            } else if (t == 'int') {
                this.intInput.show();
                this.valueInput = this.intInput;
            } else if (t == 'float') {
                this.floatInput.show();
                this.valueInput = this.floatInput;
            } else if (t == 'date') {
                this.dateInput.show();
                this.valueInput = this.dateInput;
            } else {
                this.textInput.show();
                this.valueInput = this.textInput;
            }
        },
     
        getValue: function() {
            return {
                field: this.fieldCombo.getValue(),
                test: this.testCombo.getValue(),
                value: this.valueInput.getValue()
            };
        }
    });

    このような入力フィールドを管理することで、正確なレイアウト、サイズ調整、外部パッチなど、CSSスタイルで要素に割り当てることができます.
    この階層にあるオブジェクトには、特別なテンプレートメソッドも用意されています.
  • onBeforeAdd

  • 新しいサブコンポーネントを追加すると、メソッドが呼び出されます.このとき、新しいコンポーネントがパラメータとして入力されたり、修正されたり、Containerを特別な方法で準備したりすることができます.falseに戻ると、追加の操作が終了します.
    Panel
    必要なUIコントロールがヘッダ、下部、ツールバーなどの要素を要求する場合、Ext.Panelは良いクラスで継承されます.
    注意:Panelはコンテナの1つで、どのレイアウトクラスがサブコンポーネントをレンダリングおよびコントロールするために使用されているかを忘れないでください.
    通常、Ext.Panelが実装するクラスは、他のUIコントロール(通常Containers、またはフォームフィールド)と協調して使用し、特定の構成のレイアウトスタイルを持つためのプログラム結合性が高い.また、その内のコンポーネントに操作を提供するコマンドは、tbar(上部ツールバー)bbar(下部ツールバー)の両方から設定して制御することができる.
    Field
    必要なUIコントロールがユーザのインタラクションを要求する場合、プログラムのデータをユーザに表示したり、サーバに発生する機能を修正したりすることができる場合、拡張されるクラスはExt.formであるべきである.TextField、またはExt.Form.NumberField.また、キーボードボタンの入れ替えに備えて、入れ替えボタン(Trigger button)が必要な場合は、Ext.form.TriggerFieldとなります.
    この階層にあるオブジェクトには、特別なテンプレートメソッドも用意されています.
  • onFocus:input入力ボックスがフォーカスされると、このメソッドの実行がトリガーされます.
  • onBlur:input入力ボックスがフォーカスを失うと、メソッドの実行がトリガーされます.

  • サブクラスはいつ必要ありませんか
    時には、子類の乱用は「鶏を殺して牛刀を使う」ことにほかならない.いくつかの特定の応用の場合、ある既存のクラスの方法が追加され、書き換えられ、このクラスのコンストラクタのインスタンス化の過程でパラメータに依存して伝達される.