何気なく使用している jQueryの$ショートカットですが、何もこれはjQuery特有のものではなく、prototype.jsといったほかのライブラリにおいても普通に使われているものであるため、複数のライブラリを併用していると競合が起きてしまいます。そのため、世に公開されているjQueryプラグインは一般的に以下のような関数で全体をラップされています。
;(function($) { $.fn.shake = function(options) { // 要素を退避 var elements = this; // 渡されたオプションとデフォルトをマージする var opts = $.extend({}, $.fn.shake.defaults, options); // 要素を1つずつ処理 elements.each(function() { for (var i=0; i<opts.shakes; i++) { $(this).animate({marginLeft: opts.x}, opts.speed) .animate({marginLeft: opts.x * -1}, opts.speed); } // 要素を元に戻す $(this).animate({marginLeft: 0}, opts.speed); }); // method chain用に要素を返す return this; }; // shakeプラグインのデフォルトオプション $.fn.shake.defaults = { speed: 'slow', shakes: 2, x: 10 }; }) (jQuery);
このように記述するとjQueryの$ショートカットはプラグイン内でのみ有効となり、プラグインの外側ではそちら側の都合で$ショートカットを自由に使うことができるので、互いに競合することがなくなります。また匿名関数の冒頭にセミコロンを付けると、「ギャーッ! このプラグインの前に読み込まれたプラグインの末尾にセミコロンが抜けていたせいでJSエラーが起きましたっ!!」といった恥ずかしいミスを防ぐことができます。
もう1つのメリットとして、プラグイン全体を匿名関数でラップするとクロージャが作成されるというのがあります。これによりプラグイン内の変数や関数が適切な名前空間において定義され、ほかのコードと競合することを防ぐことができます。
;(function($) { $.fn.shake = function(options) { // 要素を退避 var elements = this; // 渡されたオプションとデフォルトをマージする var opts = $.extend({}, $.fn.shake.defaults, options); // 要素を1つずつ処理 elements.each(function() { doshake($(this), opts); }); // method chain用に要素を返す return this; }; // 内部用関数 - ガクブル実行 function doshake($obj, opts) { for (var i=0; i<opts.shakes; i++) { $obj.animate({marginLeft: opts.x}, opts.speed) .animate({marginLeft: opts.x * -1}, opts.speed); } // 要素を元に戻す $obj.animate({marginLeft: 0}, opts.speed); }; // shakeプラグインのデフォルトオプション $.fn.shake.defaults = { speed: 'slow', shakes: 2, x: 10 }; }) (jQuery);
1つ前のサンプルでプラグインは匿名関数でラップされました。これにより、匿名関数の中ではプライベート関数を普通に定義することができます。もちろん外部から直接この関数を呼ぶことはできません。パブリックメソッドとプライベートメソッドを分離することでプラグインのソースコードを整理することができ、より精度の高いものに成長させることができます。
HTML5 には、HTML の名前空間に属さないユーザーオリジナルの属性を定義することができる機能が備わっています。これを独自データ属性と呼びます。良く知らない、より詳しく知りたいという方は、こちらのページをご参照ください。
独自データ属性をサポートすると、プラグインのユーザーがオプションを渡すための方法が1つ増えることになります。また、オプションをHTML要素に持たせることで、JavaScriptのコードが複雑化するのを軽減することができます。
;(function($) { $.fn.shake = function(options) { // 要素を退避 var elements = this; // 要素を1つずつ処理 elements.each(function() { // 渡されたオプションおよび独自データ属性をデフォルトにマージする var opts = $.extend({}, $.fn.shake.defaults, options, $(this).data()); doshake($(this), opts); }); // method chain用に要素を返す return this; }; // 内部用関数 - ガクブル実行 function doshake($obj, opts) { for (var i=0; i<opts.shakes; i++) { $obj.animate({marginLeft: opts.x}, opts.speed) .animate({marginLeft: opts.x * -1}, opts.speed); } // 要素を元に戻す $obj.animate({marginLeft: 0}, opts.speed); }; // shakeプラグインのデフォルトオプション $.fn.shake.defaults = { speed: 'slow', shakes: 2, x: 10 }; }) (jQuery);
<div id="square1" data-shakes="4"> <h2 id="toc-square1">#square1</h2> <span>shake x 4</span> </div> <div id="square2" data-shakes="10"> <h2 id="toc-square2">#square2</h2> <span>shake x 10</span> </div>
jQueryプラグインには静的関数を追加することができます。これによってプラグインに、ショートカットメソッドを付けたり、さらなる機能の拡張を行ったりなどが可能となり、より柔軟性を高めることが期待できます。
;(function($) { $.fn.shake = function(options) { // jquery.shake3.jsと同じ処理…… }; // 内部用関数 - ガクブル実行 function doshake($obj, opts) { // jquery.shake3.jsと同じ処理…… }; // 追加するためのベースを定義 $.shake = {}; // 静的関数 1 $.shake.yurayura = function($obj) { var opts = { speed: 1000, shakes: 10, x: 20 }; doshake($obj, opts); }; // 静的関数 2 $.shake.gakuburu = function($obj) { var opts = { speed: 25, shakes: 100, x: 10 }; doshake($obj, opts); }; // shakeプラグインのデフォルトオプション $.fn.shake.defaults = { // jquery.shake3.jsと同じ処理…… }; }) (jQuery);
これら jQuery プラグインの静的関数を呼び出すには以下のようにします。
$.shake.yurayura($('div')); $.shake.gakuburu($('div'));
いかがでしょうか。ここまでご紹介してきた知識だけでもある程度のプラグインは作れてしまいます。そう考えると割とハードルは低く感じられたりしませんか?
ではjQueryプラグインの基礎は習得できたので、今度は少しばかり本格的なプラグインにステップアップしてみましょう。
Copyright © ITmedia, Inc. All Rights Reserved.