もっと便利に!jQueryでラクラクサイト制作(実践サンプル付き)

第8回タブプラグインを作ってみよう(後編)

前回つくったタブパネルスクリプトをもとにして、タブプラグインを作ってみましょう。プラグインを作る、というと何か難しいことのように聞こえるかもしれません。前回作ったタブパネルスクリプトのように、なにも難しいことはありません。まずはプラグインについて少し考えてみましょう。

jQueryプラグインについて

前回の始めに言及したように、プラグインとは、既に完成しているJavaScriptファイルを読み込み、実行するだけで簡単に利用できるものを指すことにします。

例えば、jQueryプラグインは通常以下のようにして実行できるようになっていると思います。

プラグイン(メソッド)の実行
jQuery(function(){
    $('div.tabArea').tabPanel();
    // 対象のjQueryオブジェトに対してメソッドを実行する
});

$('div.tabArea')に対して、tabPanelというメソッドを実行するという意味ですね。メソッドを実行するだけで、ある程度の機能を提供できれば、それは立派なプラグインです。

function関数とメソッド

function関数

まずはメソッドについておさらいをしましょう。JavaScriptでは、何か機能をまとめるときに、functionという関数を使います。もっとも簡単なfunctionは以下のようなものです。sample()を実行すると、FirebugのConsoleに「Hello world」という文字列が表示されるはずです。

functionの例
function sample(){
    alert('Hello world');
}
 
sample(); // 実行する
functionの例 実行結果
functionの例 実行結果

メソッド

メソッドとは、あるオブジェクトに対して実行する関数を指します。jQueryプラグインにおけるメソッドの特徴として、関数と違うのは、あるオブジェクトをthisというキーワードで受け取ることができる、ということです。

例をあげてみます。

メソッドの例
(function($){
    $.fn.sample = function(){
        console(this);
    }
})(jQuery);
 
jQuery(function($){
    $('div').sample(); // メソッドを実行する
});
メソッドの例 実行結果
メソッドの例 実行結果

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

jQuery(function($){ ~ });

jQueryのメソッドや処理を実行する場合は、この中に記入します。window.onloadよりも早いタイミング、DOM Readyの段階で処理が実行されます。

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

カプセル化(隠蔽)と言い、最初の($)を一番最後の(jQuery)として認識させます。

実行するものはjQuery(function($){});にまとめて入れてしまえばいいのですが、プラグインなど、そのファイル単体で実行予定がないものはjQuery(function($){});に入れる必要はありません。そのまま書いてしまうと、他の場所で$を使っている場合に干渉してしまうので、jQueryプラグインを作成する際には、(function($){})(jQuery);内に入れると、その中では$はjQueryとして認識され、安全に定義することができます。

タブパネルスクリプトの関数化とメソッド化

前回作ったスクリプトは以下ですが

タブパネルスクリプト - JS
jQuery(function($){
    var tabArea = $('div.tabArea');
    var tabPanel = $('div.tabPanel',tabArea);
    var tab = $('ul.tab li',tabArea);
    
    var tabSet = function(target){
        var targetTabId = $('a',target).attr('hash');
        
        tab.removeClass('active');
        tabPanel.hide();
        $(target).addClass('active');
        $(targetTabId).show();
    }
    
    tab.click(function(){
        tabSet(this);
        return false;
    }).each(function(){
        if($(this).hasClass('active')){
            tabSet(this);
        }
    });
    
    if(tabPanel.filter(':visible').length!=1){
        tab.eq(0).addClass('active');
        tabPanel.not(':first').hide();
    }
});

このスクリプトをメソッドにすればいいだけの話なのです。

function関数にする

メソッドにする前に、functionにしてみましょう。functionにするのは簡単で、function funcName(){}で囲うだけですが、それだけでは拡張性がないので、タブ関数を実行する対象を渡すことにします。例えば今は、div.tabAreaに対してのみしか実行することができませんが、これを変えることができるようになります。

タブパネルスクリプト関数化 - JS
function tabPanel(target){ // 引数で対象要素を渡す
    var tabArea = $(target); // 引数から要素を受け取りjQueryオブジェクトとして保存しておく
    var tabPanel = $('div.tabPanel',tabArea);
    var tab = $('ul.tab li',tabArea);
    
    var tabSet = function(target){
        var targetTabId = $('a',target).attr('hash');
        
        tab.removeClass('active');
        tabPanel.hide();
        $(target).addClass('active');
        $(targetTabId).show();
    }
    
    tab.click(function(){
        tabSet(this);
        return false;
    }).each(function(){
        if($(this).hasClass('active')){
            tabSet(this);
        }
    });
    
    if(tabPanel.filter(':visible').length!=1){
        tab.eq(0).addClass('active');
        tabPanel.not(':first').hide();
    }
}

上から2行を見てください。対象にする要素を引数で渡すことができます。ただし、渡す要素は前回決めたルールに則っていることが前提条件になります。このfunction関数を実行するには以下のようにします。

タブパネルスクリプト関数を実行する - JS
jQuery(function($){
    tabPanel('div.tabArea');
});

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

では準備ができたところで、いよいよjQueryオブジェクトのメソッドにしてみましょう。まずは、jQueryオブジェクトのメソッドを作るときの作法を知る必要があります。といっても、とても簡単で以下のようにするだけです。

メソッドの登録と実行 - JS
(function($){
    // メソッドの登録
    $.fn.tabPanel = function(){
        // ここに処理を書く
        // この中では渡したjQueryオブジェクトをthisとして扱うことができる
    }
})(jQuery);
 
// メソッドの実行
jQuery(function($){
    $('div.tabArea').tabPanel();
});

上記の例では、tabPanelメソッド内では、div.tabAreaをthisとして扱うことができます。つまり、先ほど作ったtabPanel関数では引数で渡していた、対象要素を引数を使わずに、thisとして扱うことができます。これをもとに、tabPanel関数をtabPanelメソッドに書き換えてみましょう。

タブパネルスクリプトメソッド化と実行 - JS
(function($){
    $.fn.tabPanel = function(){
        var tabArea = $(this); // this == $(object)
        var tabPanel = $('div.tabPanel',tabArea);
        var tab = $('ul.tab li',tabArea);
        
        var tabSet = function(target){
            var targetTabId = $('a',target).attr('hash');
            
            tab.removeClass('active');
            tabPanel.hide();
            $(target).addClass('active');
            $(targetTabId).show();
        }
        
        tab.click(function(){
            tabSet(this);
            return false;
        }).each(function(){
            if($(this).hasClass('active')){
                tabSet(this);
            }
        });
        
        if(tabPanel.filter(':visible').length!=1){
            tab.eq(0).addClass('active');
            tabPanel.not(':first').hide();
        }
    }
})(jQuery);
 
// 実行する
jQuery(function($){
    $('div.tabArea').tabPanel();
});

機能の拡張

1)複数のタブパネルに対応する

メソッド化までが終わりました。これでプラグインは完成・・・ではなく、もう少し突っ込んで考えてみましょう。このメソッドは、現在はひとつのタブパネルしか作ることができません。jQueryオブジェクトに複数のdiv.tabAreaが入っていたとしても、その数分実行する、という処理が入っていないためです。まずは複数のタブパネルに対応するための処理を追加してみましょう。

複数の要素を含んだjQueryオブジェクトに対して、その数分同じ処理を行う場合は、eachメソッドを使うのでした。つまり、eachメソッドを加えるだけです。

注意しておくべき点は、eachメソッドの中ではthisはeachメソッドを実行しているjQueryオブジェクトを指すので、tabPanelを実行する対象の要素とは異なるということです。

機能の拡張(1⁠⁠- JS
(function($){
    $.fn.tabPanel = function(){
        var tabArea = $(this); // this == $(object)
        
        // eachメソッドを使って複数のjQueryオブジェクトに対しても処理を実行する
        tabArea.each(function(){
            var tabPanel = $('div.tabPanel',this); // eachメソッドの中ではthisが変わる
            var tab = $('ul.tab li',this);
            
            var tabSet = function(target){
                var targetTabId = $('a',target).attr('hash');
                
                tab.removeClass('active');
                tabPanel.hide();
                $(target).addClass('active');
                $(targetTabId).show();
            }
            
            tab.click(function(){
                tabSet(this);
                return false;
            }).each(function(){
                if($(this).hasClass('active')){
                    tabSet(this);
                }
            });
            
            if(tabPanel.filter(':visible').length!=1){
                tab.eq(0).addClass('active');
                tabPanel.not(':first').hide();
            }
        });
    }
})(jQuery);
 
jQuery(function($){
    $('div.tabArea').tabPanel();
});

当然、対象にする要素はタブパネルのマークアップルールに則っている必要があります。

2)タブ切り替え時にエフェクトを追加するオプションを実装する

現在のタブパネルメソッドは、タブの切り替え時は、特にエフェクトなどなく、表示非表示を切り替えているだけです。せっかく、jQueryを使っているので、もともとあるメソッドのfadeInを使って、切り替え時にエフェクトを選べるようにしてみましょう。選べるようにするには、オプションとして引数で渡し、キーとパラメータがあればそちらで実行し、なければ元々の表示非表示で実行する、といった形を取るのがベストです。

引数に入る値が、必須またはなくても影響が内場合は問題ないですが、オプション自体必須ではないので、以下のように複数の引数として扱うのは、あまりいい方法とは言えません。

オプションの渡し方(1⁠⁠- JS
(function($){
    $.fn.tabPanel = function(option1,option2){
    
        var show = option1 ? option1 : 'show';
        var duration = option2 ? option2 : null;
    
        alert(show);
        alert(duration);
    }
})(jQuery);
 
jQuery(function($){
    $('div.tabArea').tabPanel('fadeIn',400);
});

もし、option2だけを指定したい場合はどうすればいいでしょうか。上記の方法では、option1は実質省略することができません。どちらかだけを指定したい、という場合にも有効なのは以下のような書き方です。

オプションの渡し方(2⁠⁠- JS
(function($){
    $.fn.tabPanel = function(options){
        var conf = $.extend({
            show: 'show',
            duration: null // nullは空という意味
        },options || {}); // optionsに値があれば上書きする
        
        alert(conf.show);
        alert(conf.duration);
    }
})(jQuery);
 
// オプションの渡し方
jQuery(function($){
    $('div.tabArea').tabPanel({
        show: 'fadeIn',
        duration: 400
    });
});

showとhideに、それぞれデフォルト値を用意しておくことで、optionsにその値があれば上書き、なければ何もせずデフォルトの値を使うようになっています。オプションの渡し方は、引数に{}を使ってパラメータを渡します。書き方は、CSSのようにキー:値というようにします。

後は値によって、動作を変える、という部分を書き換えます。つまり、show()となっているところを、オプションでfadeInを渡している場合は、fadeIn(duration)にすればいいということになります。

メソッドの呼び出し方

メソッドの呼び出し方は、今まで見てきた方法では、$(object).method()でした。

メソッド呼び出し 1 - JS
$(object).fadeIn(400);

しかし、この方法ではmethodをオプションの値によって変えるということができないので、$(object)[method]()という呼び出し方に変えています。

メソッド呼び出し 2 - JS
$(object)['fadeIn'](400);

どちらでも同じ意味です。後者では、method部分が、show、fadeInのどちらでも対応することができます。前者ではそれができないのです。

オプションの値によって呼び出すメソッドを変える サンプル - JS
// conf.show: 'show'
// conf.duration: null
$(object)['show']();
// これは $(object).show()と同じ
 
// conf.show: 'fadeIn'
// conf.duration: 400
$(object)['fadeIn'](400);
// これは $(object).fadeIn(400)と同じ

あとは、上記に併せて切り替え部分のshowを書き換えるだけです。実際に書き換えてみましょう。

機能の拡張(2⁠⁠- JS
(function($){
    $.fn.tabPanel = function(options){
        var tabArea = $(this);
        var conf = $.extend({
            show: 'show',
            duration: null
        },options || {});
        
        tabArea.each(function(){
            var tabPanel = $('div.tabPanel',this);
            var tab = $('ul.tab li',this);
            
            var tabSet = function(target){
                var targetTabId = $('a',target).attr('hash');
                
                tab.removeClass('active');
                tabPanel.hide();
                $(target).addClass('active');
                $(targetTabId)[conf.show](conf.duration); // 書き換えた
            }
            
            tab.click(function(){
                tabSet(this);
                return false;
            }).each(function(){
                if($(this).hasClass('active')){
                    tabSet(this);
                }
            });
            
            if(tabPanel.filter(':visible').length!=1){
                tab.eq(0).addClass('active');
                tabPanel.not(':first').hide();
            }
        });
    }
})(jQuery);
 
jQuery(function($){
    $('div#tabArea1').tabPanel();
    $('div#tabArea2').tabPanel({
        show: 'fadeIn',
        duration: 300
    });
    $('div#tabArea3').tabPanel({
        show: 'slideDown',
        duration: 200
    });
});

以上でタブパネルプラグインが完成しました。オプションでfadeInを渡さずに、slideDownを渡してもいいかもしれませんね。プラグインの作成自体はとても簡単なので、ぜひ何か作ってみてください!

おすすめ記事

記事・ニュース一覧