自從前幾天幫同事Survey了可凍結列、欄的GridView的解決方案後,反應出奇熱烈... 大家熱烈地提出許多希望能"更方便使用"的"好點子"。啊! 腦海中浮現經典的場景: User看完Prototype後,興奮地提出更多的規格需求,一片歡樂中,唯有一人悶悶不樂、背脊發涼、冷汗直流 --- 負責Coding的那個可憐蟲...

看人口渴,貼心奉上一杯茶,誰知,張三問能不能少糖去冰多加檸檬,李四則嚷著想改成加蛋不加槓丸。

不過,愈是複雜的Scenario,就愈能突顯jQuery的威力,害不服輸的我又熱血起來,所以...

有興趣的人可以看一下線上展示,打勾並按【隱藏選取列】可以把部分資料列藏起來、也可以輸入列號後移至指定的表格列,最後還實作了尋找會自動捲動到所在位置並反白顯示關鍵字的功能(一直按尋找會自動找下一筆吻合者)。

多虧jQuery,程式寫起來比想像中簡短,而且用到的API還挺多的: after, attr, remoteAttr, addClass, css, evt.target, toggle, find, end, $.browser.ie, offset, position, val, scrollTop, scrollLeft, text, html, is, filter, each, click...

    <script type="text/javascript">
        $(function() {
            //在表格裡塞入選取欄位
            $("#GridView1 th:nth-child(1)")
            .after("<th><input type='checkbox' id='cbxSelAll' /></th>");
            $("#GridView1 td:nth-child(1)")
            .after("<td><input type='checkbox' class='clsHideCbx' /></td>");
            //配合SuperTable的多Table同步處理,加上列號
            $("#GridView1 tr").each(function(i) {
                $(this).attr("rowidx", i)
                .find("td").each(function(j) {
                    $(this).attr("pos", i + "_" + j);
                });
            });
            //設定SuperTable
            $("#GridView1").toSuperTable({ width: "640px", height: "480px", fixedCols: 3 })
            .find("tr:even").addClass("altRow");
            //加上全選/全不選功能(.sFHeader為配合SuperTable才加)
            $(".sFHeader #cbxSelAll")
            .click(function() {
                if (this.checked)
                    $(".clsHideCbx").attr("checked", "checked");
                else
                    $(".clsHideCbx").removeAttr("checked");
            });
            //加上隱藏/顯示功能
            $("#btnHide,#btnShowAll").click(toggleRow);
            //隱藏/顯示共用一個事件,由evt.target判別按的是哪一顆
            function toggleRow(evt) {
                var show = (evt.target.id == "btnShowAll");
                var rowSet = (show) ?
                    $(".sFData tr:not(:visible)") : $(".sFData .clsHideCbx:checked").closest("tr");
                rowSet.toggle(show)
                //一般情況到hide()即可,以下這段是為了SuperTable而加的
                //把捲動區裡那一份<table>對應的資料列也同步藏起來
                .each(function() {
                    $(".sData tbody tr[rowidx=" + $(this).attr("rowidx") + "]").toggle(show);
                });
                $(".sData tbody").find(".altRow").removeClass("altRow")
                .end().find("tr:visible:even").addClass("altRow");
                //修正IE隱藏結尾會不齊的問題
                if ($.browser.msie) {
                    var fixedColZone = $(".sFDataInner");
                    var cellZone = $(".sData table");
                    var p1 = fixedColZone.offset().top;
                    var p2 = cellZone.offset().top;
                    if (p1 != p2) {
                        fixedColZone.css("top", (p2 - fixedColZone.parent().offset().top) + "px");
                    }
                }
            }
 
            function getPosVal(s) {
                return parseInt(s.replace("px", ""));
            }
 
            $("#btnScroll").click(function() {
                scrollToRow($("#rowIdx").val());
            });
 
            //捲動到指定列數
            function scrollToRow(rowIdx) {
                //IE下有一列的位移,鋸箭法校正
                if ($.browser.msie && !isNaN(rowIdx))
                    rowIdx = parseInt(rowIdx) - 1;
                var x = $(".sData tr[rowidx=" + rowIdx + "]");
                if (x.length > 0) {
                    //alert($(".sData").scrollTop() + "," + x.position().top);
                    $(".sData").scrollTop(
                        $(".sData").scrollTop() +
                        x.position().top);
                }
            }
            //捲動到指定的欄數
            function scrollToCol(colIdx) {
                var x = $(".sData td:eq(" + colIdx + ")");
                $(".sData").scrollLeft($(".sData").scrollLeft() + x.position().left);
            }
 
            //保留所有Cell的集合
            var allCells = $(".sData #GridView1 td");
 
            $("#btnFind").click(function() {
                var keywd = $("#keywd").val();
                //先找到上次的焦點
                var focusIdx = 0;
                var hasPrevFocus = false;
                allCells.filter("td[findfocus]").each(function() {
                    focusIdx = allCells.index(this);
                    //將focus移除
                    $(this).removeAttr("findfocus")
                    //去除Highlight
                    .html($(this).text());
                    hasPrevFocus = true;
                });
                //由焦點開始往後找
                allCells.filter("td:gt(" + focusIdx + ")")
                .each(function() {
                    var td = $(this);
                    if (td.text().indexOf(keywd) > -1) {
                        var p = td.attr("pos").split("_");
                        scrollToRow(p[0]);
                        var cell = allCells.filter("td[pos=" + td.attr("pos") + "]");
                        cell.attr("findfocus", "true")
                        .html(cell.text().replace(keywd, 
                            "<span style='background-color:yellow;'>" + keywd + "</span>"));
                        scrollToCol(p[1]);
                        return false;
                    }
                });
                if (!allCells.is("td[findfocus]")) {
                    if (hasPrevFocus) {
                        if (confirm("已搜尋至結尾,要從頭開始再找一次嗎?"))
                            $("#btnFind").click();
                    } else
                        alert("找不到指定的關鍵字!");
                }
            });
 
        });
    </script>
    <style type="text/css">
    .clsLinkButton  
    { font-size: 9pt; cursor: pointer; text-decoration: underline; color: Blue; }
    #rowIdx { width: 20px; text-align: right; }
    #spnCmdBar { font-size: 9pt; margin-left: 15px; }
    </style>
</head>
<body>
<span id="spnCmdBar">
關鍵字: <input type="text" id="keywd" style="width: 80px;" /> 
<input type="button" id="btnFind" value="尋找" />&nbsp;
移至第<input type="text" id="rowIdx" value="1" />
<input type="button" value="捲動吧! 表格" id="btnScroll" /></span>
<span id="btnHide" class="clsLinkButton" style="margin-left: 150px;">隱藏選取列</span>
<span id="btnShowAll" class="clsLinkButton">顯示全部</span>

這只是個jQuery Coding Demo,不是產品或解決方案的發表會,大家要冷靜,關於功能面的提議不要太熱烈吶~~~ Coding的部分倒歡迎大家討論。


Comments

# by Joey

你是我的神!

# by Ammon

關鍵字部分有個 :contains 可以用 http://docs.jquery.com/Selectors/contains#text

# by Jeffrey

to Ammon, 謝謝補充,在以上的程式範例可用contains()取代indexOf(),寫成filter("td:gt(" + focusIdx + "):contains(" + keywd+ ")"),程式碼又會更簡潔。不過,keywd可能會出現")"之類的字元,會有要Escape的問題。這部分我還沒想出好方法。 寫Code時本來野心更大,想說還可以加入模糊比對(Regular Expression)之類的邏輯,所以特別用each一一抓出來,以便可以自己組出各式精彩的if條件進行判別,結果... 嘿嘿,在虎頭蛇尾中劃上句點。

# by Ark

可不可以幹掉FarPoint Spread 7這鬼東西 (專跑 VBscript in IE 其他都死) edit的狀態 鎖定cell的型別(int ,date, text or double ) 不給user 亂key onblur 抓出第幾row第幾欄 並且有cell_leave ,cell_onclick 等event 可加自己的function 運算:比如我要得到這row 裡 1,3,5,7的加總值 放到第10 col

# by Jeffrey

to Ark, 聽起來這些需求用jQuery都可以簡單做到,Case-By-Case客製還OK,要達到包成元件可以適用不同情境彈性組合運用,恐怕就是一番不小的工程,阿彌陀佛... XD

# by Howie

Spread還挺好用的呀..(煙)

# by citypig

flexigrid 可以動態調整表格大小、欄寬、顯示欄位... 也是用 jQuery 站長要不要順便整合看看? http://www.flexigrid.info/

# by Jeffrey

to citypig, Flexgrid看起來挺強的,還是Pure jQuery Code, 改造潛力無限,有時間來瞧一下,感謝推薦。

# by alan

黑大您好,剛試了一下,只能說您太強了 小弟剛測了一個問題 就是當點了欄位頭的CheckBox,就會全選沒錯 可是當我把第一筆的勾勾取消,按下隱藏勾選 照理只會秀第一筆的資料條,可是顯示的卻是只有"料號" 後面庫存的數字都不見了!這是何解呢?

# by Jeffrey

to alan, 嘿... 被你抓到蟲蟲了。 $(".sFData tr:not(:visible)") : $(".clsHideCbx:checked").closest("tr") 這一列有問題,要改成 $(".sFData tr:not(:visible)") : $(".sFData .clsHideCbx:checked").closest("tr") 才對。測了一下,該Bug應該已排除。

# by 萧萧

如果遇到分页怎么搞呢,这些功能是比较好,最好是能加上分页的就完美了

# by Maxi

暗黑大,這一下沒有打包下載回來玩嗎?

# by ddt

版主您好 請教我該怎麼樣讓分頁show出來呢 感恩歐

# by ddt

版主您好 請教您 我該怎麼樣讓 分頁 show 出來呢 感恩感恩

# by Jeffrey

to ddt, 萧萧, 這種凍結模式我想多半應用的情境是一口氣載入表格全部內容,再用捲動的檢視內容,我倒沒有把它改造成分頁檢視的動機。不要一次載入全部,捲到哪再預先載入之後要顯示的內容倒是挺實用的改良(有點像噗浪河道的拖拉操作概念),評估了一下,頗具難度,只能看未來是否能累積足夠的熱血再攻頂看看。(或是有高手達人願意露兩手讓大家見識一下,歡迎之至)

# by ddt

版主您好 謝謝您的回應 我的問題是說 gridview 下方自動生成的分頁項 套入js 之後就不見了, 可否給個方向呢 謝謝嚕

# by 大元

我用感動的態度欣賞你

# by gym

楼主 IE8下不好用 这个问题有解决吗? 58963034@163.com

# by thtomas

版主: 我想請問一下,如果要凍結表頭兩列的話,要如何修改呢? 因為有自訂多表頭的需求,謝謝~

# by thtomas

版主: 如果一個頁面有兩個GRIDVIEW的話,似乎只有一個gridview可以正常顯示耶...另一個就便回原形,無法有凍結的效果...可否有辦法解決?

Post a comment