[jQuery] ウィジェットを作る (1)

通常のjQueryプラグインの定義では冗長になりがちな、イベント管理やサブメソッドの実装などなどをオブジェクト指向的にわかりやすく一貫性のある記述で実現できる(多分合ってる)、jQuery UIの$.widgetについての備忘録のようなものです。

はじめに

まずは「jQuery UI 公式ページ」から.jsを入手します。
とりあえずのところは$.widgetが使えさえすればいいので、UI CoreのWidgetにだけチェックを入れてダウンロード。

ダウンロードした.zipにはjQuery本体も同梱されています。
テスト用に以下の環境を用意した想定で進めていきます。

ウィジェットの定義

jquery.test.myWidget.jsにウィジェットを定義していきます。

まずは以下のような即時関数パターンで、jQueryを引数に取って呼び出されるようにしておきます。

(function($) {
	
})(jQuery);

$が常にjQueryのエイリアスである事を期待しない等を意図する、jQueryプラグインの定義ではお決まりの記述です。以後は全てこの関数の中に書いていきます。

(function($) {
	// ウィジェットの定義
	$.widget('test.myWidget', {
		// オプション、メソッドの定義
	})
})(jQuery);

$.widget()を呼び出し、第一引数でウィジェット名を名前空間付きで渡します。そして第二引数のオブジェクトで、ウィジェットが持つオプションやメソッドを定義していきます。

optionsについて

第二引数の中でoptionsという名前で定義されたオブジェクトは、そのウィジェットのデフォルト設定として扱われます。

(function($) {
	// ウィジェット定義
	$.widget('test.myWidget', {
	
		// デフォルト設定
		options: {
			content: 'hoge'
		}

	})
})(jQuery);

そしてこの設定は、以下のようにしてウィジェット呼び出し時に値を上書きすることができます。

<!-- ウィジェット呼び出しの例 -->
~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		// オプションを上書きして呼び出し
		$("#myWidget").myWidget({content: 'fuga'});
	})
</script>
~

呼び出し側で都度設定を変えられるので、ウィジェットの汎用性が高まります。

メソッドについて

_initという名前で定義された関数は初期化メソッドとなり、ウィジェット呼び出しの際に自動的に呼び出されます。

また、全てのメソッド内では、this.optionsでoptionsに、this.elementでウィジェット呼び出し元要素のjQueryオブジェクトにそれぞれアクセスすることができます。

(function($) {
	// ウィジェット定義
	$.widget('test.myWidget', {
	
		// デフォルト設定
		options: {
			content: 'hoge'
		},

		// 初期化処理として自動的に呼び出される
		_init: function() {
			var opts = this.options; // optionsの参照
			var elm = this.element; // 呼び出し元要素(jQuery)の参照
			elm.html(opts.content);
		}

	})
})(jQuery);

そして_initと同じようなメソッドに_createがあり、こちらは_initよりも前に呼び出されるようです。

(function($) {
	// ウィジェット定義
	$.widget('test.myWidget', {
	
		// デフォルト設定
		options: {
			content: 'hoge'
		},

		// _createは_initより前に呼び出される
		_create: function() {
			this.id = '00001';
		},

		// 初期化処理として自動的に呼び出される
		_init: function() {
			alert(this.id); // '00001'
			var opts = this.options; // optionsの参照
			var elm = this.element; // 呼び出し元要素(jQuery)の参照
			elm.html(opts.content);
		}

	})
})(jQuery);

(参考記事: jQuery UI $.widget の _init と _create の違い | blog.bumberboom)

その他任意のメソッド定義は、基本的にメソッド名の頭に_(アンダースコア)が付けられたものはプライベートメソッド、それ以外はパブリックメソッドとして定義され、ウィジェット内ではどちらの場合もthis.メソッド名で参照・呼び出しができます。

(function($) {
	// ウィジェット定義
	$.widget('test.myWidget', {
	
		// デフォルト設定
		options: {
			content: 'hoge'
		},

		// 初期化処理として自動的に呼び出される
		_init: function() {
			this._update();
		},

		// プライベートメソッド
		_update: function() {
			var opts = this.options;
			var elm = this.element;
			elm.html(opts.content);
		},

		// パブリックメソッド
		setContent: function(str) {
			this.options.content = str;
			this._update();
		}

	})
})(jQuery);

イベントについて

イベントは_triggerを使ってトリガすることができます。

this._trigger(callbackName, event, data);

イベントがトリガされると、optionsのcallBackNameに対応する関数が呼び出されます。
イベントタイプの値は’ウィジェット名’+’callbackName’を全て小文字にしたものが暗黙的に設定されます。

(function($) {
	// ウィジェット定義
	$.widget('test.myWidget', {
	
		// デフォルト設定
		options: {
			content: 'hoge',
			onUpdate: function(e) {
				alert(e.type); // 'mywidgetonupdate'
			}
		},

		// 初期化処理として自動的に呼び出される
		_init: function() {
			this._update();
		},

		// プライベートメソッド
		_update: function() {
			var opts = this.options;
			var elm = this.element;
			elm.html(opts.content);
			this._trigger('onUpdate'); // イベントをトリガ
		},

		// パブリックメソッド
		setContent: function(str) {
			this.options.content = str;
			this._update();
		}

	})
})(jQuery);

optionsにあるものなので、これも呼び出し側で上書きできます。

<!-- ウィジェット呼び出しの例 -->
~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		// オプションを上書きして呼び出し
		$("#myWidget").myWidget({
			content: 'fuga',
			onUpdate: function() {
				alert('更新されました')
			}
		});
	})
</script>
~

バインドもできます。

<!-- ウィジェット呼び出しの例 -->
~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		$('#myWidget')
		.myWidget()
		.bind('mywidgetonupdate', function(){
			console.log('更新されました');
		});
	})
</script>
~

ウィジェットの呼び出し

下記は、最も単純なウィジェット呼び出しの例です。

~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		$('#myWidget').myWidget();
	})
</script>
~

optionsの値を上書きする場合は、引数にオブジェクトを渡します。

~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		$('#myWidget').myWidget({content: 'fuga'});
	})
</script>
~

optionsの値を後から取得したい場合は、第一引数に’option’、第二引数に取得したいプロパティの名前を渡せば、対応する値が返されます。第一引数は’options’ではなく’option’なのに注意。

~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		$('#myWidget').myWidget({content: 'fuga'});
		var content = $('#myWidget').myWidget('option', 'content');
		alert(content); // 'fuga'
	})
</script>
~

引数にメソッド名を文字列で渡せば、対応するパブリックメソッドの呼び出しができます。パブリックメソッドへの引数は第二引数以降に記述します。
メソッド側で何か意図的に戻り値を設定していない限り、メソッドチェーンは維持されます。

~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		$('#myWidget')
		.myWidget({content: 'fuga'})
		.myWidget('setContent', 'piyo');
	})
</script>
~

ウィジェットを呼び出した時、呼び出し元要素(jQueryオブジェクト)の$.data()に$.test.myWidgetをnewしたもの(インスタンス)がウィジェット名で格納されます。このインスタンスはウィジェット定義中のthisの参照と同じものです。

そしてその参照を使えば、各メソッドを以下のようにして呼び出すこともできます。

~
<div id="myWidget"></div>
<script type="text/javascript">
	// DOM構築完了後
	$(function() {
		var widget = $('#myWidget').myWidget({content: 'fuga'}).data('myWidget');
		widget.setContent('piyo');
		widget._update(); // 'mywidgetonupdate'
	})
</script>
~

とても書きやすい(?)ですが、しかしこれだとプライベート(のような)メソッドも呼び出せてしまえますね。
それにチェーンも切れてしまいますし、というかそもそもjQueryのルールに則してないような気もするし、なんともビミョーな感じです。

とりあえず

以上がjQueryのウィジェット定義の基本的なところです。
ちょっと疲れてきたので$.widgetのその他の機能や、より実践的なことは次回以降にまとめていきたいと思います。

参考にさせて頂いたサイト(順不同)

jQuery UI (英語サイト)
jQuery UIの$.widgetがOOPしてた – zudolog
jQuery UI $.widget の _init と _create の違い – blog.bumberboom
Understanding jQuery UI widgets: A tutorial – Hacking at 0300 (英語サイト)
jQuery UI Widget Factory (英語サイト)

関連記事

・ [jQuery] ウィジェットを作る (1)
[jQuery] ウィジェットを作る (2)
[jQuery] ウィジェットを作る (3)

「[jQuery] ウィジェットを作る (1)」への3件のフィードバック

  1. >optionsについて
    長い間困っていたことが解説されていて大変助かりました。どうもありがとうございました!

    1. >> たぬき さん
      お返事遅れてごめんなさい。
      コメントありがとうございます!お役に立てて何よりです。

コメントを残す

メールアドレスが公開されることはありません。


+ 六 = 15