






















































































































使用方法:
































/**//// <summary>
/// 方法编号:05
/// 方法名称:SetMultiLayerHeader
/// 内容摘要:创建DataGrid多层表头
/// 算法思路:建立一个ArrayList(1)来放置表征表头的ArrayList(2),通过这种结构来自动生成多层表头
/// 数组2的格式要求为:"内容,[rowspan/colspan],[colspan/colspan的值],[样式哈希表]"(带[]的可选)
/// 其中[样式哈希表]的为:key/value的对应关系,如Hashtable_style.Add("Font-size","12pt");
/// </summary>
public void SetMultiLayerHeader(DataGrid m_grid,
System.Web.UI.WebControls.DataGridItemEventArgs e,
ArrayList m_headers)
![]()
{
e.Item.Visible = false;
//处理特殊情况
if (m_grid.Controls.Count <= 0)
![]()
{
return;
}
Table m_tb = (Table)m_grid.Controls[0];
int m_iTmp = 0;
处理多行表头的实体#region 处理多行表头的实体
foreach (object obj in m_headers)
![]()
{
DataGridItem m_dg = new DataGridItem(0,0,ListItemType.Header);
ArrayList m_arrHeader = (ArrayList)obj;
TableCell[] m_cells = new TableCell[m_arrHeader.Count];
for (int i=0; i< m_cells.Length; i++)
![]()
{
m_cells[i] = new TableCell();
object[] m_arr = (object[])m_arrHeader[i];
m_cells[i].Text = m_arr.GetValue(0).ToString(); //赋header文字
if (m_arr.Length > 1) //如果有行列属性
![]()
{
if (m_arr.GetValue(1).ToString().ToLower() == "rowspan")//如果有rowspan属性
![]()
{
m_cells[i].RowSpan = Convert.ToInt32(m_arr.GetValue(2));
}
else if (m_arr.GetValue(1).ToString().ToLower() == "colspan")//如果有colspan属性
![]()
{
m_cells[i].ColumnSpan = Convert.ToInt32(m_arr.GetValue(2));
}
//处理单元格的样式
if (m_arr.Length >= 4)
![]()
{
if (m_arr.GetValue(3) != null)
![]()
{
Hashtable m_hsStyles = (Hashtable)m_arr.GetValue(3);
![]()
if (m_hsStyles.Count > 0)
![]()
{
System.Collections.IDictionaryEnumerator m_style = m_hsStyles.GetEnumerator();
for (int j = 0; j < m_hsStyles.Count; j++)
![]()
{
m_style.MoveNext();
m_cells[i].Style.Add(m_style.Key.ToString(),m_style.Value.ToString());
}
}
}
}//if (m_arr.Length > 4) 结束
}//if (m_arr.Length > 1) //如果有行列属性 结束
}// for (int i=0; i< m_cells.Length; i++) 结束
//将cell加入DataGridItem
foreach (TableCell c in m_cells)
![]()
{
m_dg.Cells.Add(c);
}
//将DataGridItem加入DataGrid
if (m_grid.AllowPaging == true || m_grid.AllowCustomPaging == true)//如果有分页
![]()
{
m_tb.Rows.AddAt(m_iTmp + 1,m_dg);
}
else //如果没有分页(处理导出excel时)
![]()
{
m_tb.Rows.AddAt(m_iTmp,m_dg);
}
m_iTmp++;
}//foreach (object obj in m_headers) 结束
#endregion 处理多行表头的实体
}
使用方法:ArrayList m_headers = new ArrayList();
ArrayList m_arrHeader1 = new ArrayList();
m_arrHeader1.Add(new object[]
{"事业部","rowspan","2"});
m_arrHeader1.Add(new object[]
{"办事处","rowspan","2"});
m_arrHeader1.Add(new object[]
{"每月合同培训完成名额数","colspan","12"});
m_arrHeader1.Add(new object[]
{"合计","rowspan","2"});
m_arrHeader1.Add(new object[]
{"积压<br>名额数","rowspan","2"});
ArrayList m_arrHeader2 = new ArrayList();
for (int i=0; i<12; i++)
![]()
{
m_arrHeader2.Add(new object[]
{(i+1).ToString() + "月"});
}
m_headers.Add(m_arrHeader1);
m_headers.Add(m_arrHeader2);
this.m_BLL.SetMultiLayerHeader(this.dgrSalesList,e,m_headers);
转载于:https://www.cnblogs.com/syveen/archive/2005/09/07/231774.html
用过layui table的都了解,layui的表格自带导出功能,只要在属性toolbar里配置即可。
如果嫌toolbar里的导出按钮不够美观,layui也友好的提供了自行定义按钮后调用导出页面数据的方法,详见:官方文档
遗憾的是:
该方法暂时并不支持对多层表头的导出。
而多层复杂表头在很多系统中都有体现,而若不想通过后台代码去做导出,只在前端页面上该如何做呢?
目录&历程
1 史前
1.1 直接使用(两种方式)
1.
下载插件:
地址:github table2excel
下载下来项目后,在项目的dist
中就有该js,在自己表格html页面引用即可使用。链接:百度云下载js
提取码:1f52/** * 使用方法该js的方法(两行代码) */ let table2excel = new Table2Excel(); // 传入你的tableId即可导出 table2excel.export($('#tableId'), "your filename");
一个解析页面元素方法:
复制走即可使用/** * * @param id:表格的id * @param fileName:导出的excel的名字 */ function exportForExcle(id,fileName){ var table = $(document.getElementById(id)).clone(); table.attr('id','datatab'); table.appendTo('body'); method5('datatab'); datatab.remove(); function method5(tableid) { var idTmr; var tableToExcel = (function() { var uri = 'data:application/vnd.ms-excel;base64,', template = '<html><head><meta charset="UTF-8"></head><body><table border="1px">{table}</table></body></html>', base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) }, format = function(s, c) {return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) } return function(table, name) { if (!table.nodeType) table = document.getElementById(table) var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML} var aTag = document.createElement('a'); aTag.download = fileName; aTag.href = uri + base64(format(template, ctx)); document.body.appendChild(aTag); aTag.onclick = function () { document.body.removeChild(aTag); } aTag.click(); } })() if(getExplorer()=='ie') { var curTbl = document.getElementById(tableid); var oXL = new ActiveXObject("Excel.Application"); var oWB = oXL.Workbooks.Add(); var xlsheet = oWB.Worksheets(1); var sel = document.body.createTextRange(); sel.moveToElementText(curTbl); sel.select(); sel.execCommand("Copy"); xlsheet.Paste(); oXL.Visible = true; try { var fname = oXL.Application.GetSaveAsFilename("Excel.xls", "Excel Spreadsheets (*.xls), *.xls"); } catch (e) { print("Nested catch caught " + e); } finally { oWB.SaveAs(fname); oWB.Close(savechanges = false); oXL.Quit(); oXL = null; idTmr = window.setInterval("Cleanup();", 1); } } else { tableToExcel(tableid) } function Cleanup() { window.clearInterval(idTmr); CollectGarbage(); } function getExplorer() { var explorer = window.navigator.userAgent ; //ie if (explorer.indexOf("MSIE") >= 0) { return 'ie'; } //firefox else if (explorer.indexOf("Firefox") >= 0) { return 'Firefox'; } //Chrome else if(explorer.indexOf("Chrome") >= 0){ return 'Chrome'; } //Opera else if(explorer.indexOf("Opera") >= 0){ return 'Opera'; } //Safari else if(explorer.indexOf("Safari") >= 0){ return 'Safari'; } } } }
1.2 上述插件使用场景解析
可用的情况:
表格的渲染方式为静态渲染,即在html的table标签中渲染好了表头与数据。
不可用的情况:
表格的渲染方式为动态渲染,即从后台查询数据来渲染表格,包括渲染动态的表头。
不可用的情况原因:
用layui.table动态渲染的表格,不会在页面的html table标签中添加doom元素。
如下图的表格(表头和数据均为动态渲染),layui渲染数据后,并不会在table
标签中append doom元素,而是会在table 标签的下面追加一个新的div,将tr th td 和数据全部存放在里面。
这也就导致了上述的两种方法均无法下载excel,就是因为:该插件在页面上找不到插件所需的doom节点与数据。
1.3 不可用场景处理
在表格渲染完成后的
done
方法中,去遍历页面上layui生成的div,抓取里面的格式与数据,来手动append到table中,再控制该table隐藏,来为导出做准备。
- 分析doom元素:能清晰看到表头和body的doom结构,里面有你需要的所有信息,包括表头的各种合并操作。
- 手动向table标签里append html。
table.render({ ... done: function (res, curr, count) { let header_tr = $("#tableId").next().find(".layui-table-header").find("tr"); let body_tr = $("#tableId").next().find(".layui-table-body").find("tr"); let header_html = ""; let body_html = ""; // 获取表头html,包括单元格的合并 $.each(header_tr,function (i,tr) { let header_th = $(tr).find("th"); header_html += "<tr>"; $.each(header_th,function (j,th) { let rowspan_num = $(th).attr("rowspan");// 行合并数 let colspan_num = $(th).attr("colspan");// 列合并数 if (rowspan_num && !colspan_num){// 只有行合并时 header_html += '<th rowspan= "'+ rowspan_num +'">'; } else if (colspan_num && !rowspan_num){// 只有列合并时 header_html += '<th colspan= "'+ colspan_num +'">'; } else if (rowspan_num && colspan_num){// 行列合并均有时 header_html += '<th rowspan= "'+ rowspan_num +'" colspan="'+ colspan_num +'">'; } else {// 没有发生单元格合并 header_html += '<th>'; } header_html += $(th).children().children().text() + '</th>';// 获取表头名称并拼接th标签 }) header_html += '</tr>'; }) // 获取表格body数据 $.each(body_tr,function (i,tr) { let body_td = $(tr).find("td"); body_html += '<tr>'; $.each(body_td,function (j,td) { body_html += '<td>' + $(td).children().text() + '</td>'; }) body_html += '</tr>'; }) $("#tableId tr").remove();// 清除之前的doom结构 $("#tableId").append(header_html).append(body_html); $("#tableId").hide(); } });
如果把最后hide()方法去掉,可以看到表格doom元素已经添加到table标签中。
1.4 处理后的使用
做了上面的处理后,就可使用第一步的方法做导出了
下面是导出方法和导出后的截图
导出的时候需要做一点小小的处理:let table2excel = new Table2Excel(); /** * 此处的show()是为了避免table2excel将hide属性带入excel中 * 导致下载后的excel中所有数据被隐藏 */ $('#tableId').show(); table2excel.export($('#tableId'), "your filename"); $('#tableId').hide();
说明:
1、上面在导出的时候如果不先把表格show显示出来。wps的excel会正常显示,而office的excel则会把所有数据隐藏。这也是这个插件强大的地方,属性也会copy到excel中去。
2、可能有的同学会觉得在这里显示出来自己添加的表格doom元素,会在页面上有一闪而过的视觉效果,亲测过,并没有。可能在网速超级卡顿的时候会出现。
3、当然,这并不是最佳的解决方法。欢迎讨论。----------------------------------------------我是分割线------------------------------------------------
更新时间:2019年10月17日 10点00分
感谢:@weixin_40915415 同学提出的固定列
的特殊情况1.5 新的情况兼容:固定列
layui在处理固定列时候的doom渲染跟活动列是不同的
如下所示:我们将第一列
承揽组
固定,再用之前版本的js去append html时会发现,固定列的header和body发生了重复(两次)
分析doom元素:
我们看到这里出现了两个header
。
原来layui在渲染有固定列的表头时,会把固定列的header和body再多渲染一次,放到样式为layui-table-fixed
的div
里。
知道这种结构,我们就好做新的处理了。
新的获取header和body doom元素的js更改如下以兼容有固定列的layui table:let header_tr = $($("#tableId").next().find(".layui-table-header")[0]).find("tr"); let body_tr = $($("#tableId").next().find(".layui-table-body")[0]).find("tr");
----------------------------------------------我是分割线------------------------------------------------
2 蜕变
2.1 table2excel_ext.js的诞生
更新时间:2020年07月28日
💕能耐心看到这儿的同学真的是爱学习的好同学,不过这儿我也给你准备了惊喜(本来觉得上面的那些是不是可以删掉了,后来一想也是自己当初的一个思路历程,就先留着吧)💕
笔者将上诉的相关操作抽出了两个方法append
和exportLayTable
添加到了table2excel.js中,直接将该修改后的js引入到需导出excel数据的页面使用即可。链接:百度云下载 table2excel_ext.js
提取码:4lsc使用方法:
var table2Excel ; table.render({ elem: '#tableId', ... done: function (res, curr, count) { table2Excel = new Table2Excel(); table2Excel.append($("#tableId")); }) }); // 导出excel点击事件 $('#exportElemId').click(function(){ let fileName = 'XXX-20200728'; table2Excel.exportLayTable($('#tableId'),fileName); });
----------------------------------------------我是分割线------------------------------------------------
2.2 新的情况兼容:合计行
更新时间:2020年10月16日
感谢:@zhang_pengpeng 同学提出的合计行
的情况layui table 自动在前端计算添加的合计行(关于怎么开启合计行,请自行查看layui 官网文档)会在body的下面重新渲染一段新的dom结构。如下图所示:
针对此种情况,笔者已经将table2excel_ext.js做了新的兼容,请返回目录2.1
进行下载使用即可。
----------------------------------------------我是分割线------------------------------------------------2.3 新的情况兼容:排除列
更新时间:2020年11月25日
感谢:@qq_26097713 同学提出的排除列(列表中一些不想被导出的列)
的情况。对于表格中的操作列,或者一些隐藏的列,又或者是一些不想导出的列。笔者对
table2excel_ext.js
做了新的兼容,来处理这种情况,下面将给出示例代码。
ps:引入新的js不会对以前的调用产生任何影响。var table2Excel ; table.render({ elem: '#tableId', ... done: function (res, curr, count) { // 排除掉的列的field数组(此参数可以不传,默认导出所有列) let exceptColumns = ["field1","field2"]; table2Excel = new Table2Excel(); table2Excel.append($("#tableId"), exceptColumns); }) });
说明:
table2Excel.append(table,exceptColumns)
方法中的第二个参数exceptColumns可以不传,不传表示导出所有列。- 其中exceptColumns数组中的值对应为渲染表格列时的
field
的值(表格中的操作列也请添加上一个field值,用于定位),如下:... { title : "姓名", field : "username",// 此处的field width : "10", align : "center" } ...
- js下载链接已做更新,请返回目录
2.1
进行下载。
在做私活的时候,有一个需求是要在页面上实现多层表头。一开始有点懵,不知道怎么来实现,我回想起在JFTT的时候,曾用过Flex版的多层表头,不过那离现在已经很久远了,久远到Flex已经被淘汰出局了。于是在网上折腾了好一会儿,终于找到一款用起来简单,效果又很不错的组件——Bootstrap-table。
Bootstrap-table还有很多强大的功能,但这篇文章我们把关注点只放在多层表头上,关注点确定后,这篇博客就很简单了,但我觉得还是很有必要推而广之——因为之前在看董卿主持的《诗词大会》,里面有很多基础的知识,竟然有很多人都答不上来,搞得我一度很“嚣张”,对老婆夸下海口说我也能过第一轮,但事实是我过不了——我也不会写“碧玉妆成一树高,万条垂下绿丝绦(tao)”中的tao字。
所以,文章不在于其难度,而在于其意义——在月球上迈上一小步和在地球上迈上一小步差别就在于“这是个人迈出的一小步,但却是人类迈出的一大步。”
#0.效果图
#1.实现方法
<html> <head> <title>多层表头</title> <link href="https://cdn.bootcss.com/bootstrap-table/1.11.1/bootstrap-table.min.css" rel="stylesheet"> <style type="text/css"> .table td, .table th { font-style: normal; font-weight: normal; text-align:center; } .bootstrap-table { width: 100%; } </style> </head> <body> <table data-toggle="table"> <thead> <tr> <th data-colspan="1">妻子</th> <th data-colspan="2">车子</th> <th data-colspan="3">房子</th> <th data-rowspan="2">总价值</th> </tr> <tr> <th>唯一</th> <th>Mini</th> <th>Smart</th> <th>90平</th> <th>149平</th> <th>别墅</th> </tr> </thead> <tbody> <tr> <td>∞</td> <td>30万</td> <td>20万</td> <td>60万</td> <td>100万</td> <td>看着办</td> <td>∞∞</td> </tr> </tbody> </table> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script> <script src="https://cdn.bootcss.com/bootstrap-table/1.11.1/bootstrap-table.min.js"></script> </body> </html>
#2.具体步骤
第一步,通过CDN引入jquery和bootstrap-table。
<link href="https://cdn.bootcss.com/bootstrap-table/1.11.1/bootstrap-table.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script> <script src="https://cdn.bootcss.com/bootstrap-table/1.11.1/bootstrap-table.min.js"></script>
第二步,第一层表头;
<tr> <th data-colspan="1">妻子</th> <th data-colspan="2">车子</th> <th data-colspan="3">房子</th> <th data-rowspan="2">总价值</th> </tr>
通过data-colspan指定二级表头横向有多少个,纵向为1;
通过data-rowspan指定二级表头纵向有多少个,横向为1;第三步,第二层表头;
<tr> <th>唯一</th> <th>Mini</th> <th>Smart</th> <th>90平</th> <th>149平</th> <th>别墅</th> </tr>
注意data-rowspan="2"对应的第二层表头就不需要指定了。
第三步,启用bootstrap-table。
<table data-toggle="table"> </table>
嗯,不需要解释了。
文章很简单,意义却大不同。
在使用layui创建表格时,需要使用layui中的数据表格多层表头的方法。多层表头是由:
colspan和rowspan这个两个参数配合使用。
例子:一个学院中的专业信息要包含着专业名称和专业编号。 效果图如下:
代码:
思路:在多层表头写出后,各个的表头位置都是没有在指定位置上,需要依靠colspan和rowspan这个两个参数把各个表头定义好位置。
(1)rowspan:行数 ,可以看到图中的序号,学院名称和操作是占两行的,所以在这三行上写上rowspan:2。专业名称和专业编号是第二层也没给上行占2行(rowspan:2),所以两个表头自然在还在第二层占1行
(2)colspan:列数,在专业信息是要包裹下面两个名称和编号的所以加上colspan:2,就可以把两列包含。
总结:不需要包含的就扩行,要包含列的就扩列。