テーブルのヘッダとフッタを固定する簡易プラグイン

更新履歴

2010-06-02
jQuery.exTable.js を Ver 0.1.2 に更新
  • jQuery 1.3 以上のバージョンで正常動作しない不具合を修正しました。
  • サンプルを含む zip ファイルでダウンロードできるようにしました。
2010-01-21
jQuery.exTable.js を Ver 0.1.1 に更新
  • セルの内包要素の膨張、table 要素の margin 設定等によるレイアウト崩れ抑止処理を追加しました
  • ヘッダ・ボディ・フッタ内のテーブル要素を取得するゲッターメソッドを追加しました
  • 記事中のソースを修正しました

だいぶ前に書いた「tableのヘッダを固定させる簡易scriptをサクっと作ってみた」というエントリに、「サンプルソースを参考にフッタも固定しようとしたけどうまくいかない」というコメントを先日頂きました。今にして見ると、前回、前々回のエントリで書いた プラグインの定義パターンという意味ではあまり参考しないほうが良さげな実装だったので、フッタ固定機能もつけて再実装してみました。

適用したプラグインの定義パターン

まずプラグインの定義パターンとしては「prototype オブジェクトを使用した定義」を採用しました。(詳しくは「jQuery プラグインの定義パターンについて調べてみた」)

//2.7 実装を prototype オブジェクトで定義
(function($){
    $.myPlugin = function( elem , option ){
        // init
    }
    $.extend( $.myPlugin.prototype,{
        hoge : function(){ ... },
        fuga : function(){ ... }
    });
    $.fn.myPlugin = function( option ) {
        return this.each(function() {
            new $.myPlugin( this , option);
        });
    };
})(jQuery);

プラグイン API の提供方法は、コールバック関数経由で API オブジェクトを引き渡す方法にしました。(詳しくは「プラグイン API の定義パターンについて調べてみた」)

//2.3 コールバック関数経由の API オブジェクトの取得
$(element).myPlugin({ onHogeClick : function( api ){
    api.execHoge();
}});

実際の実装

jquery.extable.0.1.1.js

(function($){
    $.ex = $.ex || {};

    $.ex.table = function(idx , targets , option){
        var o = this,
        c = o.config = $.extend({} , $.ex.table.defaults , option);

        //処理対象となった要素を保持
        c.targets = targets;
        c.target = c.targets.eq(idx);
        c.index = idx;

        //新設するウィジェットの外枠を生成
        c.container = $('<div class="ex-table-container">' +
            '<div class="ex-table-head"><table/></div>' +
            '<div class="ex-table-body"></div>' +
            '<div class="ex-table-foot"><table/></div>' +
            '</div>');

        //ウィジェットのヘッダ、ボディ、フッタ枠の取得と幅調整
        c.head = c.container.find('> div.ex-table-head').css({
            'padding-right':c.scrollbarWidth
        });
        c.foot = c.container.find('> div.ex-table-foot').css({
            'padding-right':c.scrollbarWidth
        });
        c.headTable = c.head.find('> table');
        c.footTable = c.foot.find('> table');
        c.body = c.container.find('> div.ex-table-body').css({
            'overflow-x' : 'hidden',
            'overflow-y' : 'scroll',
            height : c.height
        });

        //処理対象テーブルの thead / tbody / tfoot の取得
        var thead = c.target.find('> thead')
            ,tfoot = c.target.find('> tfoot')
            ,tbody = c.target.find('> tbody');

        //幅を固定する
        o._fixedWidth(thead);
        o._fixedWidth(tfoot);
        o._fixedWidth(tbody);
        c.container.width(c.target.width() + c.scrollbarWidth + 1);
        
        //新設するウィジェットの外枠をページに挿入
        c.target.after(c.container);
        
        //ウィジェットのヘッダ、フッタ枠に thead と tfoot を挿入
        c.target.find('> thead').appendTo(c.head.find('> table'));
        c.target.find('> tfoot').appendTo(c.foot.find('> table'));
        c.target.appendTo(c.body);

        //テーブル要素の margin をクリア、table-layout でレイアウトを固定化
        $([c.target[0],c.headTable[0],c.footTable[0]]).css({
            'table-layout':'fixed',
            'margin':0
        });
    
        //初期化時のコールバック関数の実行
        if( c.onInit ){
            c.onInit.apply( c.targets , [ o ] );
        }
    }
    $.extend($.ex.table.prototype,{
        _fixedWidth : function(stack){
            var cols = stack.find('> tr:eq(0) > *');
            cols.each(function( idx ){
                var col = cols.eq(idx);
                col.width(col.width()).css('overflow','hidden');
            });
        },
        getIndex : function(){
            return this.config.index;
        },
        getTargets : function(){
            return this.config.targets;
        },
        getTarget: function(){
            return this.config.target;
        },
        getContainer : function(){
            return this.config.container;       
        },
        getHead : function(){
            return this.config.head;        
        },
        getHeadTable : function(){
            return this.config.headTable;       
        },
        getBody : function(){
            return this.config.body;        
        },
        getBodyTable: function(){
            return this.config.target;
        },
        getFoot : function(){
            return this.config.foot;        
        },
        getFootTable : function(){
            return this.config.footTable;       
        }
    });
    
    $.ex.table.defaults = {
        scrollbarWidth :16,
        height : 200,
        onInit : null
    }
    $.fn.exTable = function(option){
        var targets = this;
        return targets.each(function(idx){
            targets.eq(idx).data(
                'ex-table',
                new $.ex.table(idx,targets,option)
            );
        });
    }
})(jQuery);
使い方

固定したいヘッダ、フッタは thead / tfoot に記述し、データ部は tbody に記述します。

<table id="example">
    <thead><tr><th>...</tr></thead>
    <tbody>
        <tr><td>...</td></tr>
        <tr><td>...</td></tr>
        ....
    </tbody>
    <tfoot><tr><td>...</tr></tfoot>
</table>

以下のように実行します。

jQuery(function($){
    $('#example').exTable();
})  

Demo

CSS を適用してみる

生成される HTML の構造は以下のようになります。

<div class="ex-table-container">
    <div class="ex-table-head">
        <table>
            <tr><th>...</tr>
        </table>
    </div>
    <div class="ex-table-body">
        <table>
            <tr><td>...</tr>
        </table>
    </div>
    <div class="ex-table-foot">
        <table>
            <tr><td>...</tr>
        </table>
    </div>
</div>

クラス名に CSS を当ててみます。

div.ex-table-container{
    background:#f0f0f0;
    border:solid 1px #d0d0d0;
}
div.ex-table-body td{
    background:#fff;
}

Demo

初期化処理用コールバック関数 onInit にて、API オブジェクト経由で各要素を取得し、CSS を当てることもできます。

jQuery(function($){
    $('#example').exTable({
        onInit : function(api){
            api.getContainer().css({
                background:'#aaccff',
                border:'solid 1px #5588aa'
            });
            api.getBody().find('td').css({
                background:'#f0f0f0'
            });
        }
    });
});

Demo

API オブジェクトは 、data() メソッドで任意のタイミングで取得することもできます。

var api = $('#example').data('ex-table');

テーブルの高さを指定する場合は、height パラメータを指定します。デフォルトは 200 になってます。

jQuery(function($){
    $('#example').exTable({
        height : 100
    });
});

プラグイン内で定義されてるのパラメータのデフォルト値を変更する場合は $.ex.table.defaults を上書きします。

$.extend($.ex.table.defaults,{
    height : 100
});
ダウンロード

こちらからどうぞ。