tableのヘッダを固定させる簡易scriptをサクっと作ってみた

更新履歴

2010-01-21
改良版を作りました。以下エントリをご覧下さい。

以前のエントリ「Ajax系ライブラリによくあるtableのヘッダ固定の仕組みを調べてみた」で調べた結果、

Javascriptで生成するなら小飼さん方式でいいんじゃないでしょうか(そっちの方が安心)。

Ajax系ライブラリによくあるtableのヘッダ固定の仕組みを調べてみた

という結論になりました。小飼さん方式っていうのはヘッダ用tableとボディ用tableを別々に用意しそれぞれのthとtdのカラム幅を合わせて、あたかもヘッダが固定化されてるように見せる方法なのですが、HTMLやCSSが煩雑になって記述がめんどくさいのが難点です。
と言うわけで tableのヘッダを固定させる簡易scriptをサクっと作ってみました。jQueryプラグインとして動作します。(もっと多機能なライブラリが必要な方はこちらにまとめましたのでご参照ください。)

サンプルページ

ソース
(function($j){
    var tableHeadFix = function(node$j, opt){
        var o=this;
        o.$j = node$j;
        o.opt = $j.extend({height:100},opt||{})
        o.thead$j = o.$j.find('thead');
        o.tbody$j = o.$j.find('tbody');
        o.resetWidth(o.thead$j.find('> tr > *'))
            .resetWidth(o.tbody$j.find('> tr:eq(0) > *'))
            .buildFrame()
        ;
        o.hFrame$j = o.frame$j.find('div.thead');
        o.hTable$j = o.hFrame$j.find('table');
        o.bFrame$j = o.frame$j.find('div.tbody');
    
        o.thead$j.each(function(idx){
            $j(this).appendTo(o.hTable$j[idx]);
        })
        o.$j.each(function(idx){
            $j(this).appendTo(o.bFrame$j[idx]);
        })
        o.bFrame$j.height(o.opt.height);
    
        return o.adjustFrameWidth().crrossBindGetter({
            wrapObject : o.frame$j,
            headTable : o.hTable$j,
            bodyTable: o.$j
        });
    
    }
    tableHeadFix.prototype={
        buildFrame : function(){
            var o=this,arr=[],html='<div><div class="thead"><table style="margin:0;"></table></div><div class="tbody" style="overflow:auto;"></div></div>';
            o.$j.each(function(idx){
                arr[idx]=($j(html).insertBefore(this)[0])
            })
            o.frame$j=$j(arr);
            return this;
        },
        resetWidth : function(node$j){
            node$j.each(function(){
                $j(this).width($j(this).width());
            })
            return this;
        },
        adjustFrameWidth : function(){
            var o=this,width=o.$j.width()+18;
            o.frame$j.width(width)
            o.hFrame$j.width(width)
            o.bFrame$j.width(width)
            return this;
        },
        crrossBindGetter : function(getter){
            for(var i in getter)for(var j in getter)getter[i][j]=this.getGetter(getter[j])
            return this;
        },
        getGetter : function(o){
            return function(){return o}
        }
    }
    $j.fn.tableHeadFix = function(opt){
        new tableHeadFix(this, opt);
        return this;
    }
})(jQuery)
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>tableHeadFix.js</title>
        <script src="../lib/jquery/jquery_1_2_6.js"></script>
        <script src="table_head_fix.js"></script>
        <script>
            jQuery(function($j){
                $j('#sample').tableHeadFix({height:150});
            })
        </script>
        <style>
            /* for design */
            th{
                background:#555;
                color:#fff;
                padding:4px;
            }
            td{
                height:3em;
                background:#fafafa;
                padding:4px;
            }
        </style>
    </head>
    <body>
        <table id="sample">
            <thead>
                <tr>
                    <th>no</th>
                    <th>program language</th>
                    <th>script?</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>javascript</td>
                    <td>script</td>
                </tr>

                以下 tr の繰り返し

            </tbody>
        </table>
    </body>
</html>
使い方
jQuery(function($j){
    $j('#sample').tableHeadFix({height:150});
})

$jでtable要素を選択しtableHeadFixメソッドを実行します。パラメータでボディtableの高さを指定できます

処理概要

こんな感じのことをしてます。jQueryのおかげです。

メソッドの追加 2008.7.31

会社の人に使わせてみたら、テーブルを包括するdiv要素のセンタリングとか、ヘッダ部テーブルのCSSの設定がやりずらかったので、以下メソッドを追加しました。

wrapObject
テーブル全体をラップするDIVノードを取得します。
headTable
ヘッダ用のTABLEノードを取得します。
bodyTable
ボディ用のTABLEノードを取得します。
メソッドチェーンの対応 2008.8.10

二度手間的だったノードの取得処理を修正し、メソッドチェーンでノードを取得できるようにしました。こんな感じで各要素のjQueryDOMノードが取得できます。

$j('#sample1,#sample2')
	.tableHeadFix({height:150})
	.headTable().css({'background':'#777'})//ヘッダtable
	.bodyTable().css({'background':'#555'})//ボディtable
	.wrapObject().css({'margin':'1em auto'})//包括div
;

こうなります。

サンプルページ

ダウンロード

「おおげさ機能は不要、単純にヘッダを固定させたいだけ」な時に使ってみてはいかがでしょうか。