最近做项目用到了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

easyui DataGrid表体单元格跨列rowspan的更多相关文章

  1. JQuery EasyUI DataGrid动态合并单元格

    /**        * EasyUI DataGrid根据字段动态合并单元格        * @param fldList 要合并table的id        * @param fldList ...

  2. EasyUI——DataGrid的自定义单元格点击事件

    1.当点击的单元格需要传递参数,并且传递的是row的值时,需要进行转义 function initCompareTable(){ $("#deviceCompareTable"). ...

  3. EasyUI DataGrid可编辑单元格

    效果如图: 首先在需要可编辑的列上添加一个editor属性,列定义为numberbox编辑类型 <th field="SCORES" editor="{type:' ...

  4. WPF:获取DataGrid控件单元格DataGridCell

    转载:http://blog.csdn.net/jhqin/article/details/7645357 /* ------------------------------------------- ...

  5. 雷林鹏分享:jQuery EasyUI 数据网格 - 合并单元格

    jQuery EasyUI 数据网格 - 合并单元格 数据网格(datagrid)经常需要合并一些单元格.本教程将向您展示如何在数据网格(datagrid)中合并单元格. 为了合并数据网格(datag ...

  6. Excel2007VBA数组和工作表及单元格的引用

    动态数组使用: https://zhidao.baidu.com/question/1432222709706721499.html 使用Redim动态数组即可. 1 2 3 4 5 6 7 8 Su ...

  7. c# WPF DataGrid 获取选中单元格信息

    private void Dg_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e) { Console.Write ...

  8. PHP使用PHPExcel删除Excel单元格指定列的方法是怎样

    有一个系统仅公司内部和外部经销商使用,在一个导出功能中公司内部员工跟外部经销商导出的列是不一样的(某些数据是不能提供给经销商的)因为导出的数据都是一样的(某些列外数据外部没有)因此并没有单独处理,而是 ...

  9. WPF备忘录(3)如何从 Datagrid 中获得单元格的内容与 使用值转换器进行绑定数据的转换IValueConverter

    一.如何从 Datagrid 中获得单元格的内容 DataGrid 属于一种 ItemsControl, 因此,它有 Items 属性并且用ItemContainer 封装它的 items. 但是,W ...

随机推荐

  1. Top 20 NuGet packages for captcha

    Top 20 NuGet packages for captcha CaptchaMvc.Mvc4 CaptchaMvc will implement your web MVC application ...

  2. PyCharm 基础设置

    设置主题:File -- Settings -- Editor -- Color & Fonts -- Font -- Scheme 设置为 Darcula 设置字体:File -- Sett ...

  3. AE插件开发的一些总结

    首先会遇到第一个问题,为什么输出的aex文件不在bin目录下,而在别的目录下.其实问题出在链接器的设置里.把这个改成自己想要的目录就OK 然后一些object的报错,直接把警告等级改成0就可以了.属性 ...

  4. 《转载》Tomcat内存设置详解

    原文地址:Java内存溢出详解 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError: Java heap space ----JVM Heap(堆)溢出 ...

  5. apache使某目录下的文件能够列表显示出来

    想要使web目录下,某目录下的文件列表显示而不是显示"You don't have permission to access / on this server" 需要在httpd. ...

  6. stylus--css 框架使用方法

      Stylus是一款需要编译的css语言,所以其本身文件不能被html直接调用,需要要编译为css文件后再进行日常的加载. stylus是一款优秀的css编译语言,需要node.js支持,第一步需要 ...

  7. 【Spring Boot && Spring Cloud系列】那些Spring Boot中踩过的坑

    一.不连接数据库启动springboot报错 Cannot determine embedded database driver class for database type NONE 原因:Spr ...

  8. laravel调用sql server存储过程并取得ReturnValue

    alter proc [dbo].[aaa](    @AgencyID int,--代理商ID    @AdminID int --结算操作人ID(管理员ID))asbegin    select ...

  9. Linux主机添加路由和端口转发

    环境(关闭防火墙和seLinux): 6A: CentOS6 7A 和 7B:CentOS 7 6A: 192.168.20.131/24 7B: 192.168.20.129/24 和 192.16 ...

  10. iOS interface适配