應該有不少人被這麼要求過吧?

"你們做的網頁表格為什麼不能像Excel一樣凍結標題列,底下捲來捲去也不會跑掉?"

前陣子看到一個不錯的Javascript Library,只用一行Code就可以輕鬆做出HTML表格列凍結的效果,剛好部門裡也常有這種需求,我就弄了一個簡單的範例。

大家可以先看Scrollable HTML Table Plugin範例,它本來是個純Javascript Library,Plugin只是做了簡單的包裝,把new ScrollableTable()一列指令再包起來,意義不大,所以我的示範裡只使用webtoolkit.scrollabletable.js,省去額外載入webtoolkit.jscrollable.js的功夫。

弄了一個虛構的DataTable,Bind到GridView上,稍作處理再var t = new ScrollableTable($("#GridView1")[0], 400, 640);,就變成以下的樣子:

完整程式碼如下:

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        DataTable t = new DataTable();
        t.Columns.Add("序號", typeof(int));
        t.Columns.Add("料號", typeof(string));
        t.Columns.Add("單價", typeof(decimal));
        t.Columns.Add("數量", typeof(int));
        t.Columns.Add("金額", typeof(decimal), "單價*數量");
        Random rnd = new Random();
        for (int i = 0; i < 200; i++)
        {
            t.Rows.Add(
                i + 1, 
                Guid.NewGuid().ToString().Substring(0, 13).ToUpper(),
                rnd.NextDouble() * 100,
                rnd.Next() * 2000);
        }
        GridView1.AutoGenerateColumns = false;
        foreach (DataColumn c in t.Columns)
        {
            BoundField bf = new BoundField();
            bf.DataField = c.ColumnName;
            bf.HeaderText = c.ColumnName;
            if (c.DataType == typeof(decimal))
                bf.DataFormatString = "{0:#,0.00}";
            else if (c.DataType == typeof(int))
                bf.DataFormatString = "{0:#,0}";
            bf.ItemStyle.HorizontalAlign =
                (!string.IsNullOrEmpty(bf.DataFormatString)) ?
                HorizontalAlign.Right : HorizontalAlign.Center;
                
            GridView1.Columns.Add(bf);
        }
        GridView1.DataSource = t;
        GridView1.DataBind();
    }
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style type="text/css">
    #GridView1 tr { border: solid 1px #f0f0f0; }
    #GridView1 td, th { padding: 3px; border: solid 1px white; }
    td, th { padding: 3px; border: solid 1px white; }
    #GridView1 thead tr { background-color: #dddddd; }
    .altRow { background-color: #ddddff; }
    </style>
    <script type="text/javascript" src="jquery-1.3.1.js"></script>
    <script type="text/javascript" src="webtoolkit.scrollabletable.js"></script>
    <script type="text/javascript">
        $(function() {
            $("#GridView1 tr:first").wrap("<thead></thead>");
            $("#GridView1 thead").insertBefore("#GridView1 tbody");
            $("#GridView1 tbody tr:odd").addClass("altRow");
            $("#GridView1").attr("cellspacing", "1");
            var t = new ScrollableTable($("#GridView1")[0], 400, 640);
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:GridView ID="GridView1" runat="server" Font-Size="9pt">
    </asp:GridView>
    </form>
</body>
</html>

由於Scrollable HTML Table需要由<thead>, <tbody>區分凍結區及捲動區,而GridView所產生的HTML Table標題列及內容列都放在<tbody>中且無<thead>,因此要做些事後加工,將標題列提取出來,另外放入新增的<thead>中,程式示範了如何jQuery wrap, insertBefore來解決這個問題,都是酷酷地一步到位,蠻值得參考的。

注意: 此解決方案無法跨瀏覽器,目前測試只有IE6, IE7, FF3可用, 不支援IE8, Safari, Chrome, Opera。

【2009-02-18 更新】找到另一個跨瀏覽器且支援標題欄、列凍結的版本,請見: GridView的標題欄、列凍結效果(跨瀏覽器版)


Comments

# by Eddy

在IE8試文章提到的Scrollable HTML Table Plugin範例 , 標題列會跑掉

# by Jeffrey

to Eddy, 對,忘了加註,Script Library有註明只支援IE 5+(IE8不OK,但當年還不存在,故未註!), FF 1.5+,我補上限制了,謝謝提醒。

# by Ammon

為了符合jQuery的精神 應該寫成下面這樣才對 XD new ScrollableTable( $("#GridView1").attr("cellspacing", "1") .find("tbody tr:odd").addClass("altRow").end() .find("tr:first").wrap("<thead></thead>").end() .find("thead").insertBefore("#GridView1 tbody").end()[0] , 400, 640);

# by Jeffrey

to Ammon, 很讚! 很有jQuery的fu~~~ 真的有貫徹"一行打死"的最高境界,哈!

# by Ike

另外找到加上 thead 的方法 http://stackoverflow.com/questions/309101/how-do-i-get-a-gridview-to-render-thead

# by JerryH

最近發現此方式也提不懶的.. <style type="text/css"> <!-- .DataGridFixedHeader {background-color: white; position:relative; top:expression(this.offsetParent.scrollTop);} --> </style> <div style="height: 500px; overflow: auto; width: 800px;"> <asp:DataGrid ...> <HeaderStyle CssClass="DataGridFixedHeader" /> </div> 參考 http://kjellsj.blogspot.tw/2005/04/fixed-header-in-aspnet-datagrid.html

Post a comment