如何使jqGrid的冻结列与自动换行一起工作

10

我正在使用最新的jqGrid 4.3.1,并尝试使用冻结列。

问题在于,我已经覆盖了默认CSS以支持单词换行(CSS解决方案可以在这个问题中查看),我认为这就是冻结列与常规列不能正确对齐的原因。冻结行的高度与网格其他部分的高度不同。这是截图.. 冻结列在红框中突出显示(由于它不是公共站点,我已经划掉了内容):

enter image description here

是否有任何方法可以使jqGrid中的冻结列与单词换行的单元格对齐?

更新

尝试使用Oleg下面的解决方案后,在Firefox中它有效,在IE8中我看不到水平滚动条(见图片)。

Firefox:

enter image description here

IE:(注意没有水平滚动条)

enter image description here

注意:

为了回答Oleg的问题,这里是我的jqGrid设置的转储:

jQuery(gridSelector).jqGrid({
    mtype: 'POST',
    toppager: true,
    url: siteRoot + controller + "/" + gridDataName + "?" + querystring,
    datatype: "json",
    colNames: names,
    colModel: model,
  shrinkToFit: false,

    imgpath: siteRoot + "Scripts/jqGrid431/themes/steel/images",
    rowNum: 20,
    rowList: [10, 20, 50, 999],
    altRows: true,
    altclass: "altRow",
    jsonReader: {
        root: "Rows",
        page: "Page",
        total: "Total",
        records: "Records",
        repeatitems: false,
        id: "Id"
    },
    search: true,
    postData: (myfilter) ? { filters: JSON.stringify(myfilter)} : {},
    //postData:  { filters: JSON.stringify(myfilter) },
    pager: pagerSelector,
    height: "auto",
    sortname: sortCol,
    viewrecords: true,
    sortorder: sortDirection,
    beforeRequest: function () {

        var grid = jQuery(gridSelector);
        if (gridprefs && gridprefs.filter) {
            grid.setPostDataItem('_search', true);
            for (var prop in gridprefs.filter) {
                var value = eval('gridprefs.filter.' + prop);
                if ('' + value != '') {
                    grid.setPostDataItem(prop, value);
                }
            }

            grid.setPostDataItem('sidx', gridprefs.scol);
            grid.setPostDataItem('sord', gridprefs.sord);
            grid.setPostDataItem('page', gridprefs.page);
            grid.setPostDataItem('rows', gridprefs.rows);
            grid.jqGrid('setGridParam', {
                sortname: gridprefs.scol,
                sortorder: gridprefs.sord,
                page: gridprefs.page,
                rowNum: gridprefs.rows
            });
        }
    },
    loadComplete: function () {

        var newCapture = "", filters, rules, rule, op, i, iOp,
                    postData = jQuery(gridSelector).jqGrid("getGridParam", "postData"),
                    isFiltering = jQuery(gridSelector).jqGrid("getGridParam", "search");

        if (isFiltering === true && typeof postData.filters !== "undefined") {
            filters = $.parseJSON(postData.filters);
            newCapture = "Filter: [";
            rules = filters.rules;
            for (i = 0; i < rules.length; i++) {
                rule = rules[i];
                op = rule.op;  // the code name of the operation
                iOp = $.inArray(op, arOps);
                if (iOp >= 0 && typeof $.jgrid.search.odata[iOp] !== "undefined") {
                    op = $.jgrid.search.odata[iOp];
                }
                newCapture += rule.field + " " + op + " '" + rule.data + "'";
                if (i + 1 !== rules.length) {
                    newCapture += ", ";
                }
            }
            newCapture += "]";
        }
        jQuery(gridSelector).jqGrid("setCaption", newCapture);
        fixPositionsOfFrozenDivs.call(this);

        $(gridSelector).supersleight({ shim: siteRoot + 'Content/Images/shim.gif' });
        if (gridprefs && gridprefs.filter) {
            for (var prop in gridprefs.filter) {
                $('#gs_' + prop).val(eval('gridprefs.filter.' + prop));
            }
            $(".ui-pg-selbox").val(gridprefs.rows);
            $(".ui-pg-input").val(gridprefs.page);
        }
        gridprefs = {};
    },
    editurl: siteRoot + controller + "/Update" + appendRoute,
    ondblClickRow: editable ?
        function (rowid) {
            jQuery(gridSelector).editGridRow(rowid, { width: 600 });
        } :
        function (rowid) { }
});

//$(gridSelector).jqGrid('navGrid', '#pager', { search: true, cloneToTop: true });
$(gridSelector).jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true });

jQuery(gridSelector).jqGrid('bindKeys', {});

if (editable) {
    jQuery(gridSelector).navGrid(pagerSelector,
        { cloneToTop: true, refresh: false
        },
        { height: 380, width: 500, reloadAfterSubmit: true, closeAfterEdit: true, url: siteRoot + controller + "/Update", zIndex: 1100 },
        { height: 380, width: 500, reloadAfterSubmit: true, closeAfterAdd: true, url: siteRoot + controller + "/Add", zIndex: 1100 },
        { reloadAfterSubmit: true, url: siteRoot + controller + "/Delete" },
        { multipleSearch: true,
            beforeShowSearch: function($form) {
                $('#searchmodfbox_' + $(gridSelector)[0].id).width(560);
            }
        });

} else {
    jQuery(gridSelector).navGrid(pagerSelector,
        { cloneToTop: true, refresh: false, add: false, edit: false, del: false },
        { }, { }, { }, { multipleSearch: true,
            beforeShowSearch: function($form) {
                $('#searchmodfbox_' + $(gridSelector)[0].id).width(560);
            }
        });
    }

    myAddButton(gridSelector, {
        caption: "",
        title: "Reload Grid",
        buttonicon: 'ui-icon-refresh',
        onClickButton: function () {
            $(gridSelector).trigger("reloadGrid");
        }
    });

}

问题是标题栏中的滚动条吗?还是下面“工作流程”标题下的单元格应该更高,与“团队”下面的单元格匹配? - ThinkingStiff
@ThinkingStiff - 都可以 :) - leora
你想在正文中打开自动换行,还是只在标题中打开呢? - ThinkingStiff
@ThinkingStiff - 两者都可以 :) - leora
6个回答

14
在jqGrid中实现冻结列是基于创建两个使用绝对定位的附加div,它们覆盖在标准表格之上。如果所有列头和表格主体的行高相同,则冻结列效果良好,但如果存在可变高度(使用CSS属性height: auto),则会导致以下结果(请参见第一个演示):

enter image description here

第一个div名为fhDiv,我用黄色标记,其中包含了列头的副本(hDiv),其中删除了最后的非冻结列。同样地,第二个div名为fbDiv,我用红色标记,其中包含了网格主体的副本(bDiv),其中删除了最后的非冻结列。您可以在这里阅读更多关于标准网格元素的信息。
在演示中,我在列标题中使用了字符换行,如答案中所述,并描述了单词换行,例如这里fhDivfbDiv的每一行的高度将独立于非冻结列的高度进行计算。因此,行的高度可以小于所需高度。
很难提出完美的解决方案,但我似乎找到了足够好的实用方法。思路是根据主区域
hDiv
bDiv
中相应行的大小,显式地设置每一行的高度来自fhDivfbDiv。因此,我扩展了fixPositionsOfFrozenDivs函数的代码,如答案所述:
var fixPositionsOfFrozenDivs = function () {
        var $rows;
        if (typeof this.grid.fbDiv !== "undefined") {
            $rows = $('>div>table.ui-jqgrid-btable>tbody>tr', this.grid.bDiv);
            $('>table.ui-jqgrid-btable>tbody>tr', this.grid.fbDiv).each(function (i) {
                var rowHight = $($rows[i]).height(), rowHightFrozen = $(this).height();
                if ($(this).hasClass("jqgrow")) {
                    $(this).height(rowHight);
                    rowHightFrozen = $(this).height();
                    if (rowHight !== rowHightFrozen) {
                        $(this).height(rowHight + (rowHight - rowHightFrozen));
                    }
                }
            });
            $(this.grid.fbDiv).height(this.grid.bDiv.clientHeight);
            $(this.grid.fbDiv).css($(this.grid.bDiv).position());
        }
        if (typeof this.grid.fhDiv !== "undefined") {
            $rows = $('>div>table.ui-jqgrid-htable>thead>tr', this.grid.hDiv);
            $('>table.ui-jqgrid-htable>thead>tr', this.grid.fhDiv).each(function (i) {
                var rowHight = $($rows[i]).height(), rowHightFrozen = $(this).height();
                $(this).height(rowHight);
                rowHightFrozen = $(this).height();
                if (rowHight !== rowHightFrozen) {
                    $(this).height(rowHight + (rowHight - rowHightFrozen));
                }
            });
            $(this.grid.fhDiv).height(this.grid.hDiv.clientHeight);
            $(this.grid.fhDiv).css($(this.grid.hDiv).position());
        }
    };

我在resizeStoploadComplete回调函数中调用了该方法。如果使用gridResize方法,则需要在stop处理程序内包含其他修复。

完整的建议可以在演示中查看,该演示将第一个演示的结果修复为以下内容:

enter image description here

更新: 答案 包含最新版本的演示: 这个


我仍在努力寻找一个有关冻结列且带单词换行的“清洁”解决方案...您是否知道这将在即将推出的版本中作为核心功能支持...感谢您提供的所有建议。 - leora
我接受了这个答案,因为它是最好的答案,但我的观点仍然是 jqGrid 应该支持这个功能,因为这似乎需要很多 hack 才能让它正常工作,并且仍然有些脆弱。我感谢你在这里的想法和见解。 - leora
@leora:我不是jqGrid的开发者。我已经向trirand(Tony)提交了功能请求和错误报告,但有时Tony对问题的看法与我不同。 :-) 我也提交了一些关于固定列的错误报告,但大部分都没有得到回复。我同意你的观点,修复jqGrid代码是最好的方法,但我不能提出比我更多的建议。 - Oleg
Oleg,感谢您分享这段代码 - 我遇到了同样的问题,您的函数解决了它。不过我确实需要稍微修改一下。我尝试设置resizeStop: fixPositionsOfFrozenDivs和loadComplete: fixPositionsOfFrozenDivs,但是这两个事件在触发时具有不同的'this'。对于loadComplete,'this'是网格表,但对于resizeStop,它是网格本身。所以,我在您的方法顶部插入了一行:var grid = this.grid || this。然后,我用“grid”(局部变量)替换了您方法中对“this.grid”的引用。现在它对我来说完美地工作了。 - Mark Shapiro
@MarkShapiro:不客气!每个新版本的jqGrid都会有一些变化,所以通常需要对代码进行一些小的调整。新年快乐! - Oleg
显示剩余9条评论

2

这是调整列宽的函数。

function updateSize(){

    //getting all lines in two tables by they id
    var lines = $("tr", this),
        flines = $("tr", "#"+$(this).attr("id")+"_frozen" );

    //setting in all frozen lines height equel to grid
    flines.each(function(i, item){

        //i%2 check because of border collapse
        $(item).height( $(lines[i]).innerHeight() - (i%2?1:0) );
    });
}

CSS规则
.ui-jqgrid tr.jqgrow td{
    height: auto;
    white-space: normal;
}

初始化

jQuery("#gfrc1").jqGrid({ 
    //options
    'loadComplete': updateSize,
    'resizeStop': updateSize
});
//Frozen Columns init
jQuery("#gfrc1").jqGrid('setFrozenColumns');

不是很好,但它能够工作。当我尝试使用setParams方法设置它时,存在一些错误,上下文会发生变化,所以最好在jqGrid初始化时执行。如果你需要设置功能,只需在你的函数中使用apply方法更新updateSize方法并保存这个上下文。
另一个问题是高度和边框合并,我真的不知道如何更好地解决这个问题 :)
还有一个展示静态数据的例子

1

假设这是您使用的CSS(来自您的链接):

.ui-jqgrid tr.jqgrow td {
    white-space: normal !important;
    height:auto;
    vertical-align:text-top;
    padding-top:2px;
}

你应该能够使用以下代码去掉滚动条(注意选择器是 .ui-jqgrid tr.jqgrow 而不是 .ui-jqgrid tr.jqgrow td):

.ui-jqgrid tr.jqgrow {
    overflow: hidden;
}

height: auto; 是导致行高变小的原因。尝试完全从 CSS 中删除它。如果这不起作用,您还可以将所有 <td> 元素设置为相同的高度或全部设置为 auto(两者都未经测试,因为您没有发布代码)。


1

试试这个:

qgrid tr.jqgrow td {

white-space: nowrap !important;

}

1
我无法让Oleg的解决方案正常工作,但是我根据他的工作做了一些东西,现在对我有用。不确定我是否错过了什么,但既然这对我有用,我想分享一下:
我还必须在我的CSS文件中添加一行。
.frozen-div{overflow:hidden;}

 var fixPositionsOfFrozenDivs = function () {
     var originalRowHeightArray = new Array();
     var gridId = $(this).attr("id");

     $("#" + gridId).find("tr").each(function () {
         originalRowHeightArray.push($(this).find("td").first().height() + 1);
     });

     $rows = $('>div>table.ui-jqgrid-btable>tbody>tr', this.grid.bDiv);

     $rows.each(function (i) {
         var rowHight = $($rows[i]).height(), rowHightFrozen = $(this).height();
         $(this).height(originalRowHeightArray[i] + "px");
     });
 };

你的解决方案对我非常有效。我遇到了同样的问题,在网格加载后调用了你的函数。现在,冻结和非冻结行更加对齐了。谢谢! - Andrew Hummel

0

我已经看过了,明白为什么会出现这个问题。

当冻结列显示时,实际上存在一些表格的重复,但只有冻结列,如果将空白设置为正常,并且在网格中的某个位置出现不等高的非冻结区域列,则开始在高度上不匹配。

表格的重复是为了不在js中重新计算表格参数而完成的,因此如果您需要此css属性,则应将gridComplete和resizeStop事件(或任何其他更改列宽度的事件)设置为以下函数:

function onChangeGrid(){
   var frozen = $("#grid_frozen tr", this),
       rows = $("#grid tr", this);

   frozen.each(function(i, item){
     var fEl = $(item),
         h = $(rows[i]).height();

     if( fEl.height() < h ){
       fEl.height(h); 
     } else {
       fEl.css("height", "auto");
     }
   });
}


$("#my_grid").jqGrid({
  gridComplete: onChangeGrid,
  resizeStop: onChangeGrid
});

这段代码没有经过测试,我只是写在这里,但应该可以正常工作,我现在还没有设置jqGrid。

祝玩得愉快 :)

顺便说一句,如果需要查看很多行的话,这个修复方法并不是很好,最好在 github 上设置问题任务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接