GridView的標題欄、列凍結效果(跨瀏覽器版)

稍早發表了GridView的標題列凍結效果,足以滿足工作上的需求,不過存在兩個缺點: 只支援FF及IE6/7、只能凍結列不能凍結欄(行)...

不甘心事情只做一半,又挖了一下,驚喜地發現另一個版本: Super Tables,可以支援Firefox 2+, Internet Explorer 5.5+, Safari 3+, Opera 9+ 以及Chrome,而且也支援直欄的凍結效果,在功能上大勝ScrollableTable,二話不說,通通包起來。

SuperTable的原理與ScrollableTable不同,它需要額外的CSS以及在Table外包一層<div>,可視範圍大小由<div> Style決定,設定時參數也較多(如:fixedCols, headerRows...),所以我寫了一個jQuery Plugin(jquery.superTable.js)把它包起來。有了Plugin的加持,只要一個toSuperTable(options)就可立即升級成有凍結效果的GridView了。

/////////////////////////////////////////////////////////////////////////////////////////
// Super Tables Plugin for jQuery - MIT Style License
// Copyright (c) 2009 Jeffrey Lee --- blog.darkthread.net
//
// A wrapper for Matt Murphy's Super Tables http://www.matts411.com/post/super_tables/
//
// Contributors:
//
/////////////////////////////////////////////////////////////////////////////////////////
////// TO CALL: 
// $("...").toSuperTable(options)
//
////// OPTIONS: (order does not matter )
// cssSkin : string ( eg. "sDefault", "sSky", "sOrange", "sDark" )
// headerRows : integer ( default is 1 )
// fixedCols : integer ( default is 0 )
// colWidths : integer array ( use -1 for auto sizing )
// onStart : function ( any this.variableNameHere variables you create here can be used later ( eg. onFinish function ) )
// onFinish : function ( all this.variableNameHere variables created in this script can be used in this function )
// margin, padding, width, height, overflow...: Styles for "fakeContainer"
//
////// Example:
// $("#GridView1").toSuperTable(
//              { width: "640px", height: "480px", fixedCols: 2,
//                onFinish: function() { alert('Done!'); } })
 
(function($) {
    $.fn.extend(
            {
                toSuperTable: function(options) {
                    var setting = $.extend(
                    {
                        width: "640px", height: "320px",
                        margin: "10px", padding: "0px",
                        overflow: "hidden", colWidths: undefined,
                        fixedCols: 0, headerRows: 1,
                        onStart: function() { },
                        onFinish: function() { },
                        cssSkin: "sSky"
                    }, options);
                    return this.each(function() {
                        var q = $(this);
                        var id = q.attr("id");
                        q.removeAttr("style").wrap("<div id='" + id + "_box'></div>");
 
                        var nonCssProps = ["fixedCols", "headerRows", "onStart", "onFinish", "cssSkin", "colWidths"];
                        var container = $("#" + id + "_box");
 
                        for (var p in setting) {
                            if ($.inArray(p, nonCssProps) == -1) {
                                container.css(p, setting[p]);
                                delete setting[p];
                            }
                        }
                        
                        var mySt = new superTable(id, setting);
 
                    });
                }
            });
})(jQuery);

完整的Demo程式如下:

<%@ 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));
        for (int i = 1; i <= 10; i++)
            t.Columns.Add("庫存" + i, typeof(int));
        Random rnd = new Random();
        for (int i = 0; i < 80; i++)
        {
            DataRow row = t.NewRow();
            row["序號"] = i + 1;
            row["料號"] = Guid.NewGuid().ToString().Substring(0, 13).ToUpper();
            row["單價"] = rnd.NextDouble() * 100;
            for (int j = 1; j <= 10; j++)
                row["庫存" + j] = rnd.Next(10000);
            t.Rows.Add(row);            
        }
        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">
    .altRow { background-color: #ddddff; }
    </style>
    <link href="superTables.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="jquery-1.3.1.js"></script>
    <script type="text/javascript" src="superTables.js"></script>
    <script type="text/javascript" src="jquery.superTable.js"></script>
    <script type="text/javascript">
        $(function() {
            $("#GridView1").toSuperTable({ width: "640px", height: "480px", fixedCols: 2 })
            .find("tr:even").addClass("altRow");
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:GridView ID="GridView1" runat="server" Font-Size="9pt" EnableViewState="false">
    </asp:GridView>
    </form>
</body>
</html>

我放了一個線上Demo在http://www.darkthread.net/MiniAjaxLab/ScrollTable ,或者你也可以下載程式包回去玩。

Keywords: fixed column, fixed header, freeze, scroll, excel, datagrid, gridview, html table, plugin, jQuery

Published 18 February 2009 12:10 AM 由 Jeffrey
Filed under: , ,


意見

# leo said on 17 February, 2009 10:18 AM

請問一下~我在使用您Demo網頁中的資料時

料號與序號那一欄的捲動速度好像與其他右側的速度不太一樣

本來以為是資料太都才會這樣

但好像只有在FF才有,我用IE試了一下沒有

這是怎麼樣的問題呢?

# Jeffrey said on 17 February, 2009 05:20 PM

to leo, SuperTable其實把Table拆成好幾個div,再用Javascript讓彼此連動,我覺得捲動上的不一致是因為Javascript在不同Browser上執行效率不夠好所致(資料表愈大愈明顯),依我測試結果,只有FF及Opera有此現象,IE, Safari, Chrome用起來都蠻順的。換句話說,這段Javascript在FF/Opera上的執行效果較差,除非針對它們去Tune Javascript Code,不然只能默默接受,呵。

# Owen said on 17 February, 2009 06:34 PM

perfect and useful

# sdtest said on 19 February, 2009 01:32 AM

当列标题较长时,此时虽然设置了标题的宽度,但标题还是平铺显示,导致该列被拉宽.不能还有什么设置吗?

# Jeffrey said on 19 February, 2009 03:18 PM

to sdtest, 不太容易想像出問題畫面,要不要給個圖示或網頁範例大家研究一下。

# Kevin said on 16 April, 2009 02:16 AM

請問一下:

是否可以動態設定以下的width與height嗎?

$("#GridView1").toSuperTable({ width: "640px", height: "480px",

因為有時GridView資料列數的總長度小於上面設定的height, 這時捲軸與GridView會分開

# Shawn said on 09 May, 2009 05:27 AM

Question from New bie:

When you call the 'toSuperTable' function, you set the width and height, $("#GridView1").toSuperTable(

{ width: "640px", height: "480px", fixedCols: 2 })            

.find("tr:even").addClass("altRow");

is it going to overwrite the default value in

jquery.superTable.js

var setting = $.extend(                    {                        width: "640px", height: "320px",

.......

# Jeffrey said on 10 May, 2009 08:37 PM

to Shawn, yes, $.extend() is used to merge default option parameters and parameters specified by caller.  It's the typical way in jQuery plugin to receive optional parameter with default values.

# Danie said on 18 May, 2009 01:43 AM

請問一下~

我把大大的SuperTables加入MasterPage就不行耶

沒有fixed的效果

可是如果用獨立的Page又可以

不知道有沒有大大可以解決套用MasterPage的問題

謝謝囉!

# Danie said on 18 May, 2009 03:45 AM

Jeffrey你好~

MasterPage的問題我已經找到了

就是ClientID的問題

這部分我已經排除了

但是我現在遇到另一個問題

就是如果Gridview在UpdatePanel裡面

也會沒有fixed的效果

關於這部分不知道大大是否有解?

謝謝~

# Jeffrey said on 18 May, 2009 04:21 PM

to Dannie, 您所說在UpdatePanel裡的狀況,是否在動態更新GridView內容後才發生fixed失效? 若是,我猜是更新GridView後沒有重新呼叫toSuperTable()的緣故。

# Danie said on 18 May, 2009 11:33 PM

to Jeffery,

的確有您說的情況

所以我在DataBind()的後面寫了一行JavaScript

string strScript = "$(function () {$('#" + gdv_List_ClientID + "').toSuperTable().find('tr:even').addClass('GridView_altRow');});";

ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "FixedGridView", strScript, true);

這樣就正常了,多謝大師提醒!

# JIS said on 20 May, 2009 08:00 PM

我在gridview中有一欄textbox讓使用者輸入數值,然後在onblur的時候觸發javascript與前一欄位做運算,最後把結果放在下一欄中顯示(innerHTML),結果發生表格欄位的寬度沒有隨著內容數值的長度變寬,總之就是變成破格重疊顯示在下一個欄位上,但是在沒有加上supertable的情形下是可以自動調整欄寬的,我再數值回填的innerHTML中加上stytle的寬度還是不動如山,還請各位高手前輩指教,謝謝

# Sean said on 26 May, 2009 08:06 PM

請教一下

1.小弟我也遇到如同Kevin的問題,當資料只有一筆,而height設超過一筆資料的高度時,水平捲軸將會與資料有一段空白間隔

2.無法支援GridView的分頁功能

另外,這真是一項好工具,感謝版主的分享

# Maxi said on 08 June, 2009 04:14 AM

我想請問,這個jQuery做的wrapper目的是甚麼?

我意思是,不用jquery也可以寫wrapper,jquery在這裡提供了甚麼幫助呢?

btw,我發現用jquery的code可讀性很低

# Jeffrey said on 08 June, 2009 03:38 PM

@Maxi, 包成jQuery Wrapper的用意是讓它具有跟其他jQuery Plugin一致的叫用方式,讓採用jQuery寫網頁的人可以用習慣的呼叫方式應用它,而不必特地切回傳統的Javascript方式。

我也認為易讀好學並不是jQuery要標榜的特色,跟Regular Expression一樣,學會一堆咒語,就可以變出魔法來。由jQuery走紅的程度來看,大家並沒有被它的低可讀性及陡峭學習曲線嚇跑。

# Maxi said on 08 June, 2009 09:01 PM

暗黑大,我現在用supertable做實驗,沒用jQuery,只是用他最基本的功能,0.3版.row,col都是fix = 1

IE可以看到table,但橫向的scrollbar沒出現

FF/chrome都是甚麼都看不到,DOM裡面是有建

會是那裡出問題嗎?

# Maxi said on 08 June, 2009 09:38 PM

暗黑大,真的不好意思,我找到FF/chrome看不到的答案了

因為ASP.NET在render時和IE會不一樣...

IE : gridview = <table/>

FF/Chrome : gridview = <div><table/></div>

所以我包在supertable外面的div的長寬,在FF/Chrome變成沒有設定...我開始明白為甚麼你要用jQuery Wrapper...

但我還是解決不了問題1,就是我的橫向scrollbar沒出現...

好像是sData的height錯了,應該要減掉scrollbar的高度

現在不知道怎麼辦,看一下jQuery好了...

# Maxi said on 08 June, 2009 10:00 PM

暗黑大,我解決了,要用javascript動態找出supertable的parentNode,再幫它加長寬就可以.不能用先定義好的div去包裹.  感謝你

# Maxi said on 09 June, 2009 01:24 AM

不好意思,又打擾了

我現在雖然可以用supertable了

但好像用IE7打開的話,再關IE7就會當掉...

是因為Javascript有memory leak嗎?

暗黑大有遇到嗎?

# lingtw said on 23 July, 2009 09:08 PM

为什么我的数据集很多的时候,速度非常慢!!!

# Tim said on 07 September, 2009 01:07 AM

請問一下.如果在Gridview 在 Item Template 中放一個TextBox Bind一個Columns ,Postback 後 TextBox 的值並非我設的值耶!!

# vien said on 28 September, 2009 07:38 PM

我也遇到在Gridview 的 Item Template 中放一個TextBox Bind一個Columns,Postback後TextBox的值

會改變(ex:本來值是"1",Postback一次後便成"1,1",在Postback一次就變成"1,1,1",看起來像是被Append上去.)

# Vicky said on 08 October, 2009 02:32 AM

請問要如何解決"捲軸與GridView分開"的問題,可否給程式範例,謝謝!!

# gym said on 24 November, 2009 05:20 PM

請問樓主  我的GRIDVIEW有隱藏列 用的樣式是

.hidden { display: none; }

<asp:BoundField DataField="acce01">

<FooterStyle CssClass="hidden" />

<HeaderStyle CssClass="hidden" Width="0px" />

<ItemStyle CssClass="hidden" Width="0px" />

</asp:BoundField>

可在程式中頁面就會亂掉  去掉CssClass="hidden" 又正常 但隱藏列就顯示出來了 有解決辦法嗎

# Richard said on 24 November, 2009 11:53 PM

请问gridview每列的宽都设定了 怎么又被自动分配了呢

# ad said on 04 December, 2009 07:57 AM

请问为什么没出现滚动条啊,这段代码有什么问题吗?

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default5.aspx.cs" Inherits="Default5" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "www.w3.org/.../xhtml1-transitional.dtd">

<html xmlns="www.w3.org/.../xhtml" >

<head runat="server">

   <title>无标题页</title>

   <link href="superTables.css" rel="stylesheet" type="text/css" />

   <script src="superTables.js" type="text/javascript"></script>

<style type="text/css">

.fakeContainer {

PADDING: 0px; MARGIN: 0px;

OVERFLOW: hidden;

WIDTH: 640px;

HEIGHT: 320px;

}

</style>

   </head>

<body>

   <form id="form1" runat="server">

     <div class="fakeContainer">

       <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="AccessDataSource1" EnableViewState="False" Width="536px">

           <Columns>

               <asp:BoundField DataField="类别名称" HeaderText="类别名称" SortExpression="类别名称" />

               <asp:BoundField DataField="产品名称" HeaderText="产品名称" SortExpression="产品名称" />

               <asp:BoundField DataField="产品销售额" HeaderText="产品销售额" SortExpression="产品销售额" />

               <asp:BoundField DataField="发货季度" HeaderText="发货季度" SortExpression="发货季度" />

           </Columns>

       </asp:GridView>

     </div>

     <asp:AccessDataSource ID="AccessDataSource1" runat="server" DataFile="~/App_Data/Northwind.mdb" SelectCommand="SELECT * FROM [1997年产品销售额]"></asp:AccessDataSource>

   </form>

</body>

<script type="text/javascript" language="javascript">

(function () {

   new superTable("GridView1", {

    cssSkin : "sDefault",

       fixedCols : 1

   });

})();

</script>

</html>

# Maxi said on 16 December, 2009 03:52 AM

暗黑兄,我遇到個大問題了

supertable用object.width, object.height來做寬,高設定

好像沒有辦法設定成100%這樣的寬度耶

我在嘗試讓他繼承parentNode的寬度也暫時沒有成功

如果想要他有比例地設寬度,還有min-width要怎麼辦?

# 煉金術士 said on 08 January, 2010 03:40 AM

請問暗黑大:

在使用這程式的同時,GRIDVIEW似乎會作REFRESH的動作?

而且似乎需要一點時間(約莫2~3秒),請問有沒有可以改善的方式呢?

謝謝!!

# Maxi said on 21 January, 2010 08:36 PM

我自己做的網頁用在IE7沒問題

但IE6 scrollbar會不見了

但用他的網頁首頁上的又沒問題

黑暗兄能分析看看是甚麼原因嗎

# Maxi said on 28 January, 2010 01:16 AM

黑暗兄,

我有個jquery plugin的問題,這個plugin應該只能用在table tag.

但plugin內又沒有做檢查,如果我丟一個其他tag進去,例如input tag. 不就會出錯了嗎?

# Jeffrey said on 28 January, 2010 02:09 AM

to Maxi, 我想可以用以下的寫法簡單過濾,只留下table:

return this.filter("table").each(function() { ...

# Bryant said on 03 February, 2010 01:47 AM

請問如何把Gridview的所有欄位都固定住並把水平捲軸拿掉,感謝您的解答

# Bryant said on 03 February, 2010 06:20 PM

您好,我把我的問題詳述一下,我的欄位只有三個,但資料筆數很多,所以只要需要固定標題列即可,但不論我設定fixedcol 0或是把寬和高放大,第三個欄位還是看不到需要把水平捲軸往右拉才行,請問題否能夠讓三個欄位都固定住並把水平捲軸拿掉,感謝您的解答。

# Jeffrey said on 05 February, 2010 05:18 PM

to 各位網友,關於Super Table,陸續累積了好多網友的提問,不過坦白跟大家說,當初為要動用這個技術解決的工作需求,受限於Javascript在表格欄位超多時的捲動效能表現無法符合User需求,最後還是決定改用Silverlight實作... 因此這部分並未深入嘗試繼續研究了。

我仍有興趣解決一些"小幅修改JS就能克服"的問題,但前題必須要請大家提供"可以示範問題所在的實際網頁範例",才好射茶包。Super Table所使用的技巧蠻Hacking的,若能簡單滿足需求很好,但必須大幅改造才能適用,我倒覺值得評估一下。(純個人意見)

# Senlin said on 09 March, 2010 09:01 AM

非常感谢楼主

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

搜尋

Go

<February 2009>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
1234567
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication