Sencha アプリでプラグインとミックスインを使う
こんにちは、ゼノフィnakamuraです。
はじめに
フレームワーククラスの機能を拡張するには、基本的には派生したクラスに新しい機能を直接書き込んでいきます。しかし、同じ機能が複数のコンポーネントに欲しい場合、プラグインもしくはミックスインとして定義する方法が最も効率が良いでしょう。プラグインやミックスインは、クラスに機能を追加してくれる別のクラスのことです。この記事では、こういったクラスがどういったものなのか、どういった違いがあり、どう機能するかを解説していきます。また、それらのコンセプトをより明確に描くために Sencha Fiddle のサンプルも追加しました。
プラグインとは何か?そしてどう使うのか?
プラグインとは Ext.Component (もしくは Ext.Component の派生クラス) に変更もしくは何かを足すクラスです。他のクラスと同じように、プラグインは Ext.define() を使い Ext.plugin.Abstract を継承して定義します。
// Ext.plugin.Abstract を継承してプラグインを // 定義する方法を示した簡単なサンプル Ext.define('Fiddle.plugin.SamplePlugin', { extend: 'Ext.plugin.Abstract', alias: 'plugin.sampleplugin', init: function (cmp) { this.setCmp(cmp); } }); |
しかし、実際は init(cmp)
メソッドを持っているクラスであればどんなクラスでもかまいません。コンポーネントが描画される前にコンポーネントのコンストラクタがそれをコールするからです。プラグインはコンポーネントの
“plugins”
config を通して追加、設定され、コンポーネントが始めて定義される場合はクラスボディにセットできますし、インスタンス化される間に config オブジェクトの中にセットできます。
[Fiddleのサンプル]
Ext.plugin.Abstract を継承してプラグインを作る場合、デフォルトで init()
、destroy()
、enable()
、disable()
メソッドがあります。これらの有効に使う方法を解説しましょう。
init()
init() メソッドはプラグインにとってのエントリーポイントです。これにより、プラグインは接続されているコンポーネントとレンダリングされる前にインタラクトすることができます。プラグインはこの段階では、クライアントコンポーネントに参照を保存しなければなりません。それはプラグイン上で定義されているメソッドが簡単に参照できるようにするためです。Ext.plugin.Abstract はプラグインを使ってコンポーネントを参照できるように2つのアクセサメソッドを提供します。
- setCmp() –
init(cmp)
内でsetCmp(cmp)
を使うと、getCmp()
が使うプラグイン上のコンポーネントへの参照をセットします。 - getCmp() – このアクセサメソッドはプラグイン上で定義されている他のメソッドが使用します
getCmp()
メソッドは特に重要です。それは、プラグインとそのメソッドはプラグイン自身スコープ内で作動するからです。つまり、this
の参照はプラグインです。プラグインを使用しているクライアントコンポーネントではありません。クライアントコンポーネントにアクセスするためのこの getter メソッドはプラグインメソッドが所有しているコンポーネントとインタラクトしなければいけない時に役立ちます。
init()
メソッドは init()
が処理される時にプラグインロジックをセットアップするかもしれません。そうでない場合は所有しているコンポーネントが描画された後にプラグインロジックをセットアップしなければいけません。例えば、ドラッグアンドドロップ領域はコンポーネントの HTML が DOM に描画された後に作られなければなりません。この場合、クライアントコンポーネントの afterrender イベントにリスナーをセットアップしなければなりません。そして、それと同時にプラグインの機能もセットアップしなければなりません。
[Fiddleのサンプル]
destroy()
プラグインの
destroy()
メソッドはクライアントコンポーネントが破棄された時にコールされます。プラグインによって作られたクラスインスタンス (例: ドラッグアンドドロップ、キーナビゲーションなど) はこのタイミングでプログラムによって破棄されなければいけません。クライアントコンポーネントのインスタンス上にセットされたコンビニエンスプロパティも null をセットするか削除します。
[Fiddleのサンプル]
enable() / disable()
enable()
メソッドは単純にプラグインの disabled プロパティを false にセットし、
disable()
メソッドは disabled を true にセットします。この機能は独自のプラグインを生成するときに拡張できます。また、先に disabled ステートを確認してからプラグインロジックを操作することができます。これは自分がどくらいの細部までプラグインを有効化/無効化したいかによって、自由に設定できるようになっています。
[Fiddleのサンプル]
プラグインにレファレンスをフェッチ
プラグインに定義づけされたメソッドは、それを使っているコンポーネントではなくプラグインのものであるため、メソッドをコールするためには参照をコンポーネントからプラグインに持ってこなければなりません。もしくは、プラグインメソッドをコンポーネントに bind することでより便利にすることもできます。 [Fiddleのサンプル]
plugin
クラスを定義する場合、plugin というプレフィックスをつけた alias を付けるとわかりやすいです (例: plugin.myplugin
)。クライアントコンポーネントがそのプラグインを使用した場合、ptype
を使ってより簡単に設定できます。
plugins: [{ ptype: 'myplugin' }] |
alias は、コンポーネントの findPlugin() メソッドを使って、プラグインの参照を検索できます。例えば、
var thePlugin = owningClass.findPlugin(‘myplugin'); |
最後に、コンポーネントの getPlugin() メソッド と pluginId を使う事で、プラグインへのレファレンスを手に入れることができます。
plugins: [{ ptype: 'myplugin', pluginId: 'myPluginId'; }] var thePlugin = owningClass.getPlugin(‘myPluginId'); |
ミックスインとは何か?そしてどう使うのか?
ミックスイン (mixin) もクラスに機能性を追加するクラスです。しかし、プラグインとは以下のような違いがあります。
- ミックスインはどんなクラスにも機能を加える事ができます。それに対してプラグインは Ext.Component クラスで使われます。
- ミックスインはクラス定義内でのみ、 “mixins” コンフィグを使って宣言します。プラグインはクラス定義もしくはクラスインスタンス上で宣言することができます。
- ミックスインはどんなクラスにミックスインしても、作動するようにデザインできます (Ext.mixin.Observable はイベントの発火やリッスンする機能をどんなクラスにでも追加できます) 。それと同時に、より特定の分野のクラスに範囲を限定して作動するようにすることも可能です (Ext.panel.Pinnable はパネルクラスにのみ追加されるようにデザインされています) 。
- ミックスインで定義されたメソッドはターゲットのクラスのプロトタイプに適用されます。
ミックスインを使ってクラスのインスタンスを作った場合、ミックスインで定義されたメソッドを直接クラスからコールします。メソッド内のスコープは所有しているクラスそのものです。 [Fiddleのサンプル] 所有クラスが持っている同じ名前のメソッドを、ミックスイン上でも定義することは可能です。この場合、ミックスインのメソッドは対象クラスのプロタイプ上にはセットされません。クラス上のメソッドをコールしても、オリジナルのクラスが定義したメソッドがコールされます。
同じ名前の ミックスインメソッドをコールする場合、所有クラス (それ以下) の ミックスインにフェッチし、直接ミックスインメソッドをコールします。直接ミックスインメソッドをコールする場合、ミックスインがスコープです。つまり、”this” がミックスインになります。[Fiddleのサンプル] 例えば、ミックスインが ‘util’ と言う ミックスインid だった場合、ミックスインで定義づけされた destroy メソッドをコールした場合はこうなります:
this.mixins.util.destroy.call(this); |
ミックスインの定義
A mixin may be any class defined by Ext.define(), though we recommend extending
Ext.Mixin
Ext.define() で定義したクラスであればミックスインになれます、しかし推奨するのは
Ext.Mixin
を継承することです。ミックスインクラスを定義する場合に、Ext.Mixin を継承する一番の利点は、「フック」を定義することができるようになることです。フックはミックスインで定義されたメソッドで、受け取るクラスに対応したメソッドの前か後に自動的にコールされます。例えば、‘after’ フックを使う事で、クラスが破棄されるとミックスインの afterDestroy()
メソッドがコールされることを確定させることができます。
mixinConfig: { after: { destroy: 'afterDestroy' } } |
“before”、 “after”、 “on”、 “extended” フックについては、Ext.Mixin API ドキュメントのトップを参照してください。
ミックスインを使う
ミックスインの推奨される使用法は、フルクラスネームを配列に指定することです。配列の順番にミックスインは処理されます。
mixins: [ 'My.utility.MixinClass' // "util" is used to reference the mixin ] |
オブジェクト記法 (次項の2番目のオプションを参照) は後方互換性を提供しています、しかし使用されるキー名がミックスインクラス上で定義された id と関係ないため、あまりおすすめできません。
Fetching a Reference to the Mixin ミックスインにレファレンスをフェッチ
クラスインスタンスからクラスのミックスインの参照をフェッチしたい場合があるかもしれません。これは、所有クラスのインスタンスの “mixins” プロパティの後にミックスインの id (例:“this.mixins.util”) をつけることで可能になります。ミックスインクラスを定義する場合は、常にユニークなミックスイン id を設定することをお勧めします。ミックスイン id をセットもしくは決定する方法は3つあります。
-
-
Ext.Mixin を継承しないのであれば、mixinId config をミックスインのクラスボディー上にセットすることができます。例えば。
mixinId: 'util'
-
もしミックスインが Ext.Mixin を継承する場合、以下のように mixinConfig で id コンフィグをセットできます。
mixinConfig: { id: 'util' }
-
Ext.Mixin を継承しないのであれば、mixinId config をミックスインのクラスボディー上にセットすることができます。例えば。
-
ミックスインはオブジェクトとしても定義できます。各ミックスインは name/id でキー付けされます。例えば:
mixins: { util: “My.utility.MixinClass” }
-
上記の方法をで id がセットされていない場合、ミックスインのフルクラスネームを使うこともできます。
Ext.define('My.utility.MixinClass'); var utilMixin = owningClass.mixins['My.utility.MixinClass'];
プラグインとミックスインの使い分け
プラグインとミックスインが何かわかったところで、どういった状況でどちらを使うべきかを疑問に思われるでしょう。同じ機能はどちらのクラスタイプでも書くことは可能ではあるので、その機能のアプリケーション内での使われ方を考えなければなりません。プラグインは、より柔軟かもしれません。それは、インスタンス上でも使えるためであり、つまりインスタンスにオーバーヘッドを加えるだけだからです。しかし、その機能が全てのクラスで必要であった場合、そのロジックをミックスインで定義した方が効率が良くなります。これは、クラスインスタンスを作るたびにプラグインインスタンスが生成されるわけではないからです。