jQueryのプラグインを作る(基本編)

jQueryの基本的なプラグインの作り方を公式サイトのマニュアルを元に自分なりの解釈を交えてまとめておきます。

jQuery: How to Create a Basic Plugin

jQueryのオブジェクトメソッド

jQueryの基本的なメソッドの書き方です。これは全てのa要素にstyle属性がインラインで設定されます。
jQueryのオブジェクトは、$.fnオブジェクトからこれらのメソッドを取得します。このオブジェクトには全てのjQueryオブジェクトメソッドが含まれています。

$( "a" ).css( "color", "red" );

つまり、jQueryのプラグインを作るには$.fnオブジェクトに独自のメソッドを設定することで作成することができます。

プラグインの基本

以下の例では、$.fnオブジェクトにgreenifyという独自メソッドを設定して、a要素でメソッドをコールしています。

$.fn.greenify = function() {
    this.css( "color", "green" );
};

$( "a" ).greenify(); // Makes all the links green

2行目のthisは、greenifyメソッドの一部なので、オブジェクトです。$(this)とすると二重でラップすることになるので、thisを用いる点に注意しましょう。

メソッドチェーンへの配慮

jQueryではメソッドチェーンが使用できますが、独自プラグインを作成する際にメソッドチェーンへの配慮が必要です。以下の例で、6行目のgreenifyメソッドに続けてaddClassメソッドがコールされています。

$.fn.greenify = function() {
    this.css( "color", "green" );
    return this;
};

$( "a" ).greenify().addClass( "greenified" );

3行目のreturn thisで自分自身(オブジェクト)をreturnしています。この記述がないとaddClassメソッドは対象のオブジェクトが存在しないことになり、コールしていますが動作しません。お作法として、オブジェクト自身をreturnするようにしましょう。

$エイリアス(別名)の保護とスコープの追加

$変数は、JavaScriptライブラリでも一般的に使われています。jQueryで別のライブラリを使用している場合には、jQuery.noConflict()でコンフリクトが発生しないように配慮する必要があります。$はjQuery関数のエイリアスであるという前提で書かれているので、他のプラグインに影響を与えず、自分のプラグインにスコープを限定させるように、jQuery関数をプラグインに渡して、パラメータを$変数にすることで他への影響をなくします。

(function ( $ ) {
    $.fn.greenify = function() {
        this.css( "color", "green" );
        return this;
    };
}( jQuery ));

プラグインでプライベートな変数を持つこともできます。プラグイン内にshade変数を設定した例が以下のようになります。

(function ( $ ) {
    var shade = "#556b2f";

    $.fn.greenify = function() {
        this.css( "color", shade );
        return this;
    };
}( jQuery ));

プラグインの最小化

プラグインを作成する場合は、$.fnオブジェクト1つで構成されるべきです。以下のコードは悪い例です。

(function( $ ) {
    $.fn.openPopup = function() {
        // Open popup code.
    };

    $.fn.closePopup = function() {
        // Close popup code.
    };
}( jQuery ));

1つの$.fnオブジェクトで実行してパラメータでアクションを制御するほうが良いコードです。

(function( $ ) {
    $.fn.popup = function( action ) {
        if ( action === "open") {
            // Open popup code.
        }

        if ( action === "close" ) {
            // Close popup code.
        }
    };
}( jQuery ));

each()メソッドの使用

jQueryのオブジェクトには、任意の数のDOM要素への参照があるため、jQueryオブジェクトはよくコレクションと呼ばれます。特定の要素(データ属性の取得、特定の位置の計算など)を操作する場合は、.each()を使用して要素をループする必要があります。

$.fn.myNewPlugin = function() {
    return this.each(function() {
        // Do something to each element here.
    });
};

thisを返すのではなく、.each()の結果を返すことに注意しましょう。.each()はすでにチェーン化可能なので、thisを返します。 これはこれまで行ってきたことよりも連鎖性を維持するためにすぐれた方法です。

オプション設定

オプションを設定できることにより、プラグインのカスタマイズ性が向上します。多くのオプションがある場合は、オブジェクトリテラルを使用することです。 いくつかのオプションを設定できるようにgreenifyプラグインを変更しましょう。

(function ( $ ) {
    $.fn.greenify = function( options ) {
        // This is the easiest way to have default options.
        var settings = $.extend({
            // These are the defaults.
            color: "#556b2f",
            backgroundColor: "white"
        }, options );

        // Greenify the collection based on the settings variable.
        return this.css({
            color: settings.color,
            background-color: settings.backgroundColor
        });
    };
}( jQuery ));
$( "div" ).greenify({
    color: "orange"
});

#556b2fのカラーのデフォルト値は、$ .extend()によってオレンジ色にオーバーライドされます。

jQueryのプラグインを作る(高度な設定)

jQuery基本編に続き高度な設定ということで、これも公式サイトのマニュアルを参考にまとめます。

jQuery: Advanced Plugin Concepts

デフォルトのプラグイン設定へのパブリックアクセスを提供

この機能を実現するには、デフォルトのプラグイン設定を公開する必要があります。 これは、プラグインユーザーが最小限のコードでプラグインをオーバーライド/カスタマイズするのが非常に簡単になるために重要です。これが関数オブジェクトを利用し始めるところです。

// Plugin definition.
$.fn.hilight = function( options ) {
    // Extend our default options with those provided.
    // Note that the first argument to extend is an empty
    // object – this is to keep from overriding our "defaults" object.
    var opts = $.extend( {}, $.fn.hilight.defaults, options );

    // Our plugin implementation code goes here.
};

// Plugin defaults – added as a property on our plugin function.
$.fn.hilight.defaults = {
    foreground: "red",
    background: "yellow"
};

12行目でdefault設定をパブリック公開しています。これでユーザーはスクリプトで以下のようなプログラムを含めることができます。

// This needs only be called once and does not
// have to be called from within a "ready" block
$.fn.hilight.defaults.foreground = "blue";

foreground値のデフォルト値を「red」から「blue」にオーバーライドしました。これでhilightメソッドを呼び出したら前景色が青に設定されます。

$( "#myDiv" ).hilight();

ご覧のように、プラグインのデフォルトのフォアグラウンドカラーを変更するために、1行のプログラムできました。 また、ユーザーは必要に応じてこの新しいデフォルト値を選択してオーバーライドすることができます。

// Override plugin default foreground color.
$.fn.hilight.defaults.foreground = "blue";

// ...

// Invoke plugin using new defaults.
$( ".hilightDiv" ).hilight();

// ...

// Override default by passing options to plugin method.
$( "#green" ).hilight({
    foreground: "green"
});

けど、う〜ん正直デフォルト値まで変更必要かな?と思った。プラグインにもよるけど、1回しかコールしない場合であればオプションでコントロールしたほうが良いように思えた。

プライベートな機能を非公開にする

プラグインの一部をオーバーライドする方法を公開することは非常に強力です。 しかし、実装にはどの部分を公開するかを注意深く考える必要があります。 公開されたら、呼び出し側の引数や意味合いの変更によって下位互換性が損なわれる可能性があることに注意する必要があります。

では、ネームスペースを混乱させることなく、実装を公開せずに、もっと多くの関数を定義する方法はあるのでしょうか? これはプライベートの仕事です。 以下のデモでは、プラグインに “debug”という別の関数を追加します。 デバッグ機能は、選択した要素の数をコンソールに記録します。 クロージャを作成するには、関数内にプラグイン定義全体をラップします。

// Create closure.
(function( $ ) {
    // Plugin definition.
    $.fn.hilight = function( options ) {
        debug( this );
        // ...
    };

    // Private function for debugging.
    function debug( obj ) {
        if ( window.console && window.console.log ) {
            window.console.log( "hilight selection count: " + obj.length );
        }
    };

    // ...

// End of closure.
})( jQuery );

jQueryプラグインのテンプレート

最後にjQueryのプラグインを作成するにあたって、最も基本的な構成をまとめました。これをベースにしてプラグインを作っていこうと思います。

(function ( $ ) {
    $.fn.NewPlugin = function( options ) {
        // オプション設定(属性: 値)
        var defaults = {


        };
        var settings = $.extend( {}, defaults, options );

        return this.each(function() {
            // メイン処理
        });
    };
}( jQuery ));

あまりごちゃごちゃ書かずにシンプルにしあげること。関数は必要な分、適宜追加する。

プラグイン作成例

この作成方法を元に作ったプラグインを記事にしました。

GitHub