zoukankan      html  css  js  c++  java
  • easyui DataGrid表体单元格跨列rowspan

    最近做项目用到了jquery easyui,其中一组DataGrid做的报表是给客户大领导看的,客户要求报表样式跟他们原有系统的一模一样(如下图1)。

    DataGrid样式好调,只是城市名称单元格跨行这个难度稍大,本着用户体验无尺度的用户价值观,无尺度的修改了easyui源代码

     
    图1 – “城市”和“名称”列跨行的处理效果

    一、分析准备:

    1、jquery版本:1.8.0;easyui版本:1.3.2
    2、首先读easyui文档,只有关于表头rowspan和colspan的配置的方式,表体装载数据的配置并没有介绍有关rowspan和colspan的,
    再仔细读,发现文档中有如下内容:

     
    图2 –DataGrid View文档描述

    初步判定render方法应该就是装载DataGrid数据的方法吧。

    3、打开jquery.easyui.min.js,代码格式明显很乱,为了提高可读性,可以使用工具格式化一下,Eclipse或者Visual Studio都有相应的快捷工具。

    搜索render方法,发现由于太多没有办法确定具体是哪一个,继续看文档,renderRow的描述“This is an option function and will be called by render function.”,说明renderRow是被render调用的。搜索renderRow,直接就可以跟踪到了,它定义在一个叫“_5ef”变量中(jquery.easyui.min.js的变量或者方法命名都是3位长度的16进制数,在文件的8276行,格式化代码之后大约在10564行,直接搜索var _5ef就能找到它了),会发现DataGrid View的所有方法都在这里。

    4、读render和renderRow方法,结合easyui文档介绍,文档和源码对比:

      Render有三个参数分别是:target, container, frozen,对应源代码就是render : function(_5f0, _5f1, _5f2)
      renderRow 的五个参数如下:target, fields, frozen, rowIndex, rowData也就是对应renderRow : function(_5fe, _5ff, _600, _601, _602)
    其中render方法是装载datagrid数据的主方法,render方法首先把数据根据记录分行,然后逐行调用renderRow方法,把每一条记录装载为datagrid表格的一行数据。
    附renderRow的五个参数解释:
      _5fe:datagrid对象,翻译过来基本上是JSON格式的字符串,需要装载的数据保存在这里面
      _5ff:表头Field集合,也就是页面中定义Datagrid的每一列的Field都保存在_5ff中
      _600: frozen顾名思义,是一个冻结标记。在本方法中,和opts.rownumbers组合成一个&&运算,用来标记是否显示行号
      _601:是行的索引,以0为初始下标
      _602:是对应行的数据,装载datagrid的数据
      其中render的功能是根据条件逐行装载需要装载的数据,应该说_5f5.push(this.renderRow.call(this, _5f0, _5f4, _5f2, i,rows[i]))调用就是装载每一行数据。
    renderRow的功能是把装载的行装载到DataGrid对应的table中,cc.push("<td field="" + _604 + "" " + _607 + ">");就是装载<td>的代码。
    因此,我们可以有如下结论:

    renderRow方法中的cc.push("<td field="" + _604 + "" " + _607 + ">");修改为cc.push("<td rowspan="" + rownumber + "" field="" + _604 + "" " + _607 + ">");的形式,就一切OK

    我们可以在需要处理的<td>标签中增加一些能够显示的数据来验证我们的思路是否正确。验证思路通过,那下一步就要处理它了

    二、初步修改

    我们可以确定,我们要把表格处理成如下图3右所示的样式

              
        图3左                图3右

    1、获取要跨行的单元格和数量:

    我们要把一个城市名称都显示的列(如上-左)做成如上(右)所示的效果,首先要明确我们在哪一行(城市如重庆,出现的第一行)需要rowspan来处理,既然有rowspan,那肯定要有rowspan的数量。因此,需要两个变量来统计跨行的那一行以及跨越的数量

    2、在起初,我们由_5fe入参可以获得所有的数据_5fe1 = $.data(_5fe, "datagrid").data.rows;,以行为记录对象的二维数组,循环rows,就可以得到每一个单元格的数据了。例:rows [i][_5ff[3]]就是获取i行对应第3(四)列的数据了,_5ff是rows对列的特殊处理
    在renderRow方法中加入以下代码:

    var _5fe1 = $.data(_5fe, "datagrid");
    var rows = _5fe1.data.rows;

    确定两个数组变量以及针对它们的处理:

    //记录需要跨列的单元格行号
    var city = [];
    //记录需要跨列的单元格跨列数量
    var cityRowspanCount = [];
    //因为我处理城市列数据是倒序处理的,对于第1行数据可能会处理不到,所以初始化city[0]和定义cityCount,
    city[0] = 1;
    var cityCount = 1;
    //处理city序列
    for (var i = rows.length - 1; i > 0; i--){
        if (rows[i][_5ff[3]] != rows[i - 1][_5ff[3]]){
            city[i] = 1;
        }
    }
    //处理city对应的数量cityRowspanCount
    for (var j = rows.length - 1; j > 0; j--){
        if (rows[j][_5ff[3]] != rows[j - 1][_5ff[3]]){
            cityRowspanCount[j] = cityCount;
            cityCount = 1;
        }
        else{
            cityCount++;
        }
        if (j == 1){
            cityRowspanCount[0] = cityCount;
        }
    }

    通过两个for循环,得到city和cityRowspanCount 两个数组,
    我们以图3的处理效果,打印城市的处理结果
        city : [1,1,,1,,,,,,1]
        cityRowspanCount : [1,2,,6,,,,,,5]
    这样,就可以用以上两个数组处理表格了,接着读renderRow方法剩下的内容,if的功能是加载表格的行号,for循环的作用就是对当前行的数据依次读取
      if (_600 && opts.rownumbers)
      for ( var i = 0; i < _5ff.length; i++)
    分析或者打印_5ff,我们可以发现它是所有列field属性的集合。确定是哪一列需要跨行处理,注意隐藏列也要算上,以0下标为初始。

    3、修改:

    // 读取表中内容
    for ( var i =  0; i < _5ff.length; i++) {
        //第四(3)列需要用rowspan合并,因此重新处理
        if (i == 3)
        {
            //对于需要装载的单元格,执行if中的语句
            if (city[_601])
            {
                var _604 = _5ff[i];
                var col = $(_5fe).datagrid("getColumnOption", _604);
                if (col) {
                    var _605 = _602[_604];
                    var _606 = col.styler ? (col.styler(_605, _602, _601) || "") : "";
                    var _607 = col.hidden ? "style="display:none;" + _606 + """ : (_606 ? "style="" + _606 + """ : "");
                    //需要装载的单元格处理rowspan为cityRowspanCount对应的数量
                    cc.push("<td rowspan="" + cityRowspanCount[_601] + "" field="" + _604 + "" " + _607 + ">");
                    if (col.checkbox) {
                        //省略…
                    }
                    cc.push("<div style="" + _607 + "" ");
                    if (col.checkbox) {
                        //省略…
                    }
                    cc.push("">");
                    if (col.checkbox) {
                        //省略…
                    }
                    cc.push("</div>");
                    cc.push("</td>");
                }
            }    
        }
        else{
            //其它列的内容按照正常模式装载
        }
    }

    通过以上修改,Datagrid单元格跨列的功能就大体实现了。

    三、完善&优化

      通过修改renderRow方法,基本实现了单元格跨列的功能,但是现在处理city和cityRowspanCount是在renderRow方法里面处理的,由于renderRow方法每装载一行数据就要执行一次,city和cityRowspanCount就要重新生成一次,不仅不符合设计逻辑,还会造成资源浪费等问题,因此把city和cityRowspanCount的定义可以放在render方法里面,提高代码执行效率(注:可能用IE8的朋友会出现表格高度出错的现象,不要着急,后面会告诉大家怎么处理)。

    1、首先在render方法中定义citycityRowspanCount并实现功能,同时为了区别renderRow方法,定义renderRowNew方法,
    参数:this.renderRowNew.call(this, _5f0, _5f4, _5f2, i, rows[i],city,cityRowspanCount)

    render : function(_5f0, _5f1, _5f2) {
        var _5f3 = $.data(_5f0, "datagrid");
        var opts = _5f3.options;
        var rows = _5f3.data.rows;
        var _5f4 = $(_5f0).datagrid("getColumnFields", _5f2);
        //begin 初始化需要rowspan的行以及数量
        var city = [];
        city[0] = 1;
        var cityRowspanCount = [];
        var cityCount = 1;
        for (var i = rows.length - 1; i > 0; i--){
            if (rows[i][_5f4[3]] != rows[i - 1][_5f4[3]]){
                city[i] = 1;
            }
        }
        for (var j = rows.length - 1; j > 0; j--){
            if (rows[j][_5f4[3]] != rows[j - 1][_5f4[3]]){
                cityRowspanCount[j] = cityCount;
                cityCount = 1;
            }
            else{
                cityCount++;
            }
            if (j == 1){
                cityRowspanCount[0] = cityCount;
            }
        }
        //end
        if (_5f2) {
            if (!(opts.rownumbers || (opts.frozenColumns && opts.frozenColumns.length))) {
                return;
            }
        }
        var _5f5 = [ "<table class="datagrid-btable" cellspacing="0" cellpadding="0" border="0"><tbody>" ];
        for ( var i = 0; i < rows.length; i++) {
            var cls = (i % 2 && opts.striped) ? "class="datagrid-row datagrid-row-alt""
                    : "class="datagrid-row"";
            var _5f6 = opts.rowStyler ? opts.rowStyler.call(_5f0, i, rows[i]) : "";
            var _5f7 = _5f6 ? "style="" + _5f6 + """ : "";
            var _5f8 = _5f3.rowIdPrefix + "-" + (_5f2 ? 1 : 2) + "-" + i;
            
            _5f5.push("<tr id="" + _5f8 + "" datagrid-row-index="" + i + "" " + cls + " " + _5f7 + ">");
         //调用新写的renderRowNew并注释原来的renderRow方法 _5f5.push(
    this.renderRowNew.call(this, _5f0, _5f4, _5f2, i, rows[i],city,cityRowspanCount)); //_5f5.push(this.renderRow.call(this, _5f0, _5f4, _5f2, i, rows[i])); _5f5.push("</tr>"); } _5f5.push("</tbody></table>"); $(_5f1).html(_5f5.join("")); }

    2、编写renderRowNew方法:

    renderRowNew : function(_5fe, _5ff, _600, _601, _602,_601a,_601b,_601c,_601d) {
        var opts = $.data(_5fe, "datagrid").options;
        var cc = [];
        // 装载行号
        if (_600 && opts.rownumbers) {
            // _603表格当前行
            var _603 = _601 + 1;
            if (opts.pagination) {
                _603 += (opts.pageNumber - 1) * opts.pageSize;
            }
            cc.push("<td class="datagrid-td-rownumber"><div class="datagrid-cell-rownumber">" + _603
                    + "</div></td>");
        }
        // 装载当前行数据
        for ( var i =  0; i < _5ff.length; i++) {
            //第3列需要用rowspan合并,因此重新写
            if (i == 3){
                //对于需要展示的单元格,才能执行if中的语句
                if (_601a[_601]){
                    var _604 = _5ff[i];
                    var col = $(_5fe).datagrid("getColumnOption", _604);
                    if (col) {
                        var _605 = _602[_604];
                        var _606 = col.styler ? (col.styler(_605, _602, _601) || "") : "";
                        var _607 = col.hidden ? "style="display:none;" + _606 + """ : (_606 ? "style="" + _606 + """: "");
                        cc.push("<td rowspan="" + _601b[_601] + "" field="" + _604 + "" " + _607 + ">");
                        if (col.checkbox) {
                            //省略…
                        }
                        cc.push("<div style="" + _607 + "" ");
                        if (col.checkbox) {
                            //省略…
                        }
                        cc.push("">");
                        if (col.checkbox) {
                            //省略…
                        }
                        cc.push("</div>");
                        cc.push("</td>");
                    }
                }    
            }
            else{
                //省略…
            }
        }
        return cc.join("");
    }

    3、通过以上的处理,就大功告成了,有问题继续看“问题处理”

    四、问题处理

    用IE8的朋友会出现表格高度不一致的现象,IE8兼容性不管怎么调都是不好用,原因是datagrid在装载完毕之后,会根据高度自动修改table样式,
    这个是在function _474(_475, _476, _477)中进行处理的,把以下几行代码注释就可以了

    //_47b += c._outerHeight();
     
    //_479.height(_47b);
    //_47a.height(_47b);
    
    //var _47d = Math.max(tr1.height(), tr2.height());
    //tr1.css("height", _47d);
    //tr2.css("height", _47d);

    --------------------------------------------
    参考资料:
    Jquery.easyui官方文档:http://www.jeasyui.com/documentation/index.php#

    转载请注明出处http://www.cnblogs.com/panzhaohui

  • 相关阅读:
    day91:luffy:基于vue+drf的路飞学城项目后端部署
    day90:luffy:基于vue+drf的路飞学城项目前端部署
    day89:luffy:使用Celery完成我的订单超时取消&Polyv视频加密播放
    day88:luffy:支付宝同步结果通知&接收异步支付结果&用户购买记录&我的订单
    day87:luffy:结算页面积分&支付宝接口
    day86:luffy:前端发送请求生成订单&结算页面优惠劵的实现
    day85:luffy:购物车根据有效期不同切换价格&购物车删除操作&价格结算&订单页面前戏
    C++中子类出现与父类同名成员函数如果调用父类函数
    C++继承方式引起子类中继承的父类属性访问权限的改变 && C++对象大小
    C++引用传递和指针传递区别
  • 原文地址:https://www.cnblogs.com/panzhaohui/p/3533999.html
Copyright © 2011-2022 走看看