layui 复杂表头多层表头的表格数据非后台导出excel

用过layui table的都了解,layui的表格自带导出功能,只要在属性toolbar里配置即可。
如果嫌toolbar里的导出按钮不够美观,layui也友好的提供了自行定义按钮后调用导出页面数据的方法,详见:官方文档
遗憾的是:该方法暂时并不支持对多层表头的导出。
而多层复杂表头在很多系统中都有体现,而若不想通过后台代码去做导出,只在前端页面上该如何做呢?

一、下载插件或使用现成的一段代码

1.下载插件:
地址:github table2excel
下载下来项目后,在项目的dist中就有该js,在自己表格html页面引用即可使用。

链接:百度云下载js
提取码:1f52

/**
 * 使用方法该js的方法(两行代码)
 */
let table2excel = new Table2Excel();
// 传入你的tableId即可导出
table2excel.export($('#tableId'), "your filename");
  1. 一个解析页面元素方法:复制走即可使用
/**
 * 
 * @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 = '{table}
'
, 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'; } } } }

二、上述插件可使用的情况与不可使用的情况

可用的情况:表格的渲染方式为静态渲染,即在html的table标签中渲染好了表头与数据。
不可用的情况:表格的渲染方式为动态渲染,即从后台查询数据来渲染表格,包括渲染动态的表头。
不可用的情况原因:用layui.table动态渲染的表格,不会在页面的html table标签中添加doom元素。
如下图的表格(表头和数据均为动态渲染),layui渲染数据后,并不会在table标签中append doom元素,而是会在table 标签的下面追加一个新的div,将tr th td 和数据全部存放在里面。
这也就导致了上述的两种方法均无法下载excel,就是因为:该插件在页面上找不到插件所需的doom节点与数据。
layui 复杂表头多层表头的表格数据非后台导出excel_第1张图片
layui 复杂表头多层表头的表格数据非后台导出excel_第2张图片


三、解决方法

在表格渲染完成后的done方法中,去遍历页面上layui生成的div,抓取里面的格式与数据,来手动append到table中,再控制该table隐藏,来为导出做准备。

  1. 分析doom元素:能清晰看到表头和body的doom结构,里面有你需要的所有信息,包括表头的各种合并操作。

layui 复杂表头多层表头的表格数据非后台导出excel_第3张图片

  1. 手动向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 += "";
            $.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 += '+ rowspan_num +'">';
                } else if (colspan_num && !rowspan_num){// 只有列合并时
                    header_html += '+ colspan_num +'">';
                } else if (rowspan_num && colspan_num){// 行列合并均有时
                    header_html += '+ rowspan_num +'" colspan="'+ colspan_num +'">';
                } else {// 没有发生单元格合并
                    header_html += '';
                }
                header_html += $(th).children().children().text() + '';// 获取表头名称并拼接th标签
            })
            header_html += '';
        })
        // 获取表格body数据
        $.each(body_tr,function (i,tr) {
            let body_td = $(tr).find("td");
            body_html += '';
            $.each(body_td,function (j,td) {
                body_html += '' + $(td).children().text() + '';
            })
            body_html += '';
        })
        $("#tableId tr").remove();// 清除之前的doom结构
        $("#tableId").append(header_html).append(body_html);
        $("#tableId").hide();
    }
});

如果把最后hide()方法去掉,可以看到表格doom元素已经添加到table标签中。

layui 复杂表头多层表头的表格数据非后台导出excel_第4张图片
layui 复杂表头多层表头的表格数据非后台导出excel_第5张图片


四、做了上面的处理后,就可使用第一步的方法做导出了

下面是导出方法和导出后的截图
导出的时候需要做一点小小的处理:

let table2excel = new Table2Excel();
 /**
 * 此处的show()是为了避免table2excel将hide属性带入excel中
 * 导致下载后的excel中所有数据被隐藏
 */
$('#tableId').show();
table2excel.export($('#tableId'), "your filename");
$('#tableId').hide();

layui 复杂表头多层表头的表格数据非后台导出excel_第6张图片
说明:
1、上面在导出的时候如果不先把表格show显示出来。wps的excel会正常显示,而office的excel则会把所有数据隐藏。这也是这个插件强大的地方,属性也会copy到excel中去。
2、可能有的同学会觉得在这里显示出来自己添加的表格doom元素,会在页面上有一闪而过的视觉效果,亲测过,并没有。可能在网速超级卡顿的时候会出现。
3、当然,这并不是最佳的解决方法。欢迎讨论。

----------------------------------------------我是分割线------------------------------------------------

更新时间:2019年10月17日 10点00分
感谢:@weixin_40915415 同学提出的固定列的特殊情况

这里有一种新的情况:固定列

layui在处理固定列时候的doom渲染跟活动列是不同的

如下所示:我们将第一列承揽组固定,再用之前版本的js去append html时会发现,固定列的header和body发生了重复(两次)

layui 复杂表头多层表头的表格数据非后台导出excel_第7张图片
分析doom元素:
layui 复杂表头多层表头的表格数据非后台导出excel_第8张图片
我们看到这里出现了两个header
原来layui在渲染有固定列的表头时,会把固定列的header和body再多渲染一次,放到样式为layui-table-fixeddiv里。
知道这种结构,我们就好做新的处理了。
新的获取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");

----------------------------------------------我是分割线------------------------------------------------
更新时间:2020年07月28日
笔者将上诉的相关操作抽出了两个方法appendexportLayTable添加到了table2excel.js中,直接将该修改后的js引入到需导出excel数据的页面使用即可。

链接:百度云下载 table2excel_ext.js
提取码:aw0q

使用方法:

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);
});

你可能感兴趣的:(layui)