基于layui 的数据表格复杂表头导出到excel文件中

本文介绍如何使用layui和js-xlsx实现复杂多级表头的Excel导出功能,包括动态表格合并及基础样式设置,如背景色和边框。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言 :

   前台表格数据导出到excel 依赖于 js-xlsx 的excel.js(Version: v1.4) , 本文实现了复杂多级表头的生成,包含 
   动态的实现'表格合并',以及 基础表格样式 (背景色、边框)。 如有不足之处还望指正,多谢!

layui table 加载

(版本2.2.45以前具体版本忘了)

  function initDataGrid(){
  dataList = [
  		{type : 'numbers',width : 30,rowspan:2 /* 行号 */
  		},
  		{title:'增加时间', field:'createTimeStr',type:'string',minWidth:83,rowspan:2,align:'center',fixed:'left'},
  		{title:'名称', field:'name',type:'string',minWidth:80,rowspan:2,align:'center',fixed:'left',render:function(row){
  			return row.name;
  		}},
  		{title:'项目名称', field:'projectName',type:'string',minWidth:130,rowspan:2,align:'center',fixed:'left',render:function(row){
  			return row.projectName;
  			}
  		},
  		{title:'编号', field:'code',type:'string',minWidth:130,rowspan:2,align:'center',fixed:'left'},
  		{title:'课题名称', field:'techName',type:'string',minWidth:140,rowspan:2,align:'center',fixed:'left'},
  		{title:'课题类别', field:'techType',type:'string',minWidth:80,rowspan:2,align:'center'},
  		{title:'时间',align:'center',colspan:2},
  		{title:'预算',align:'center',minWidth:160,colspan:maxYear - minYear+2}
  		];
  if(organizationWrite){  // 指定位置插入列
  	dataList.splice(3,0,{title:'项目部名称', field:'organizationName',type:'string',minWidth:130,rowspan:2,align:'center',fixed:'left'})
  };
  var eachYear = [];
  for (var m = 0; m <= maxYear - minYear; m++) {  // 动态行数据添加
  	var yeartitle = minYear + m;
  	var yearAmount = m+1;
  	eachYear.push({
  				title : yeartitle + '年',
  				field : 'budgetAmount',
  				type : 'string',
  				minWidth : 60,
  				align : 'center',
  				render: function(row) {
  					var ret = "";
  					if(!changeRow){
  						changeRow = row.id;
  					}else if(changeRow != row.id){
  						// 一条数据遍历完, 对数据进行归零处理
  						changeRow = row.id;
  						fork = 0;
  						fort = 0
  					}
  					var rowBudgets = row.budgets;
  					if(!!rowBudgets){
  					let f = fort;
  					if(fort == yearAmount){
  						f = 0;fort=0;
  					}
  						for (; f < yearAmount; f++) { // fort 列下标
  							
  							for (let fork = 0; fork < rowBudgets.length; fork++) { // fork 数据下标
  								
  								if (rowBudgets[fork].budgetTime == minYear + fort ) {
  									
  									var returnStr =  rowBudgets[fork].budgetAmount;
  									 
  									ret = returnStr;
  									break;
  								}
  							}
  						}
  					}
  					fort ++;
  					if(row.totalRow) return "<span style='color:red'>" +ret+"</span>"; // 合计行标红
  					return ret;
  				}
  			})

  }
  dataList.push.apply(dataList,[
  		{title:'名单', field:'techList',type:'string',minWidth:180,rowspan:2,align:'center'},
  		{title:'证据',align:'center',colspan:6},
  		{title:'已核算费用',colspan:2,align:'center'},
  		{title:'核算费用比例(%)',    field:'costRatio',type:'string',width:153,rowspan:2,align:'center'},
  		{title:'状态', field:'techStatus',hide:true,width:70,rowspan:2,align:'center'},
  		{title:'审核状态', field:'auditStatus',type:'string',minWidth:110,rowspan:2,align:'center'},
  		{title: '操作', fixed:'right',field:'hideExcel', minWidth: 190 ,align:"center", allowHide: false,render: function (row){
  			return " 操作 删除、编辑、修改  等";
  		}}
  ]);
  	
  dataListSec = [
  		{title:'起始日期', field:'startTime',type:'string',minWidth:80,align:'center'},
  		{title:'完成日期', field:'endTime',type:'string',minWidth:80,align:'center'},
  		{title:'合计', field:'totalAmount',type:'string',minWidth:80,align:'center',render:function(row){
  				return "计算出来的合计数";
  			}
  		}
  	]
  dataListSec.push.apply(dataListSec,eachYear);
  dataListSec.push.apply(dataListSec,[
  		{title:'数量'1, field:'zlCount',type:'int',width:70,align:'center'},
  		{title:'数量2', field:'gfCount',type:'int',width:70,align:'center'},
  		{title:'数量3', field:'cxCount',type:'int',width:70,align:'center'},
  		{title:'数量4', field:'jdCount',type:'int',width:70,align:'center'},
  		{title:'数量5', field:'lwCount',type:'int',width:70,align:'center'},
  		{title:'其他', field:'qtCount',type:'int',width:50,align:'center'},
  		{title:'核算日期(年月)', field:'accountionDate',type:'string',width:128,align:'center'},
  		{title:'核算研发费用', field:'accountionExp',type:'string',width:100,align:'center'}]);
   var url = "www.baidu.com/后台请求数据url";
  grid1 = laytable.render({
  	id:'maingrid1',
  	elem:'#maingrid1',
  	url: url,
  	delayLoad : true,		//true:在初始化表格时不加载数据
  	cols: [/*sort:false,fixed:false|'right',rowspan:1,colspan:1,render:function(row, rowindex, rows) */
  	dataList,dataListSec
  		],
  	page : true,
  	limit: 30,
  	heightDiff : 0,
  	even: false, //关闭隔行背景,
  	trackSelectedRow:true,//选中行高亮显示 .layui-table-row-active
  	onLoadData : function(data){//当从后台加载到数据的时候触发
  	},
  	onRowClick : function(index, row){//当点击一行的时候触发
  		//console.log(index+':'+JSON.stringify(row));
  	},
  	onRowDblClick : function(index, row){//当双击一行的时候触发
  		//console.log(index+':'+JSON.stringify(row));
  	},
  	done : function(res, curr, count) {  // 数据加载完成后 执行
  	}
  	});
}

layui 表头样式

在这里插入图片描述 ## 2. 复杂表头数据组装

// 复杂表头表格导出
function exportFile(id) {
  // 根据传入tableID获取table内容
  var bodys = $("div[class='layui-form layui-border-box layui-table-view'] .layui-table-box table").get(1); // 获取数据
  var btrs = Array.from(bodys.querySelectorAll("tr"))
  var btdslength = Array.from(btrs[0].querySelectorAll("td")).length;
  // 根据传入tableID获取表头
  var headers = $("div[class='layui-form layui-border-box layui-table-view'] .layui-table-box table").get(0); // 获取表头
  var htrs = Array.from(headers.querySelectorAll('tr'));
  var bodysArr = new Array();
  var point =new Array();  // 行,列
  for(var pi =0; pi<=htrs.length; pi++){
  	point[pi] = new Array();
  }
  point[0][0] ="qd"; // 起点
  var mergeArr = [];
  for (var j = 0; j < htrs.length; j++) {    // 遍历tr 
  	var titles = [];
  	var hths = Array.from(htrs[j].querySelectorAll("th"));
  	var titleAll = {};
  	var pointIndex = 0;
  	var pindx = 0;  // 起点遍历位置
  	for (var i = 0; i < hths.length; i++) {  // 遍历 th 
//			if(hths[i].textContent !="课题资料" && hths[i].textContent !="操作" ){  // 排除 不需要导出的列,数据td 需要同步 排除
  			var clazz = hths[i].getAttributeNode('class');
  			var colspan = hths[i].getAttributeNode('colspan'); // 表头占用列数
  			var rowspan = hths[i].getAttributeNode('rowspan'); //,表头占用行数
  			if(!colspan){
  				colspan = 1;
  			}else{
  				colspan = parseInt(colspan.value);
  			}
  			if(!rowspan){
  				rowspan = 1;
  			}else{
  				rowspan = parseInt(rowspan.value);
  			}
  			// 判断数据起始填写位置
  			for(;pindx < btdslength; pindx ++){
  				if(j == 0 || point[j][pindx] == "qd"){
  					titles.push(hths[i].innerText);
  					for(var temp = 0; temp < colspan-1;temp++){
  						titles.push(null);
  					}
  					mergeArr.push({s:{r:j,c:pindx},e:{r:j+rowspan-1,c:pindx+colspan-1}}); // 添加合并数据参数  r的差R表示向下扩展R个单元格,c 的差C表示想右扩展C个单元格
  					for(var qdi = 0; qdi<colspan ;qdi ++){
  						point[j+rowspan][pindx+qdi] = "qd"; // 添加完数据 ,添加起点记录
  					}
  					pindx = pindx+colspan;
  					break;
  				}else{
  					titles.push(""); // 不能为null, 为null 会影响表格样式的设置
  				}
  			}
//			}
  	}
//		bodysArr.unshift(titles);// 将标题行置顶添加到数组
  	bodysArr.push(titles);
  }
  var widthArr = [];
  for (var j = 0; j < btrs.length; j++) {
  	var contents = [];
  	var btds = Array.from(btrs[j].querySelectorAll("td"));
  	for (var i = 0; i < btds.length; i++) {
//			if(btds[i].dataset.field !="attachment" && btds[i].dataset.field !="hideExcel" ){  // 排除 不需要导出的列,titles 需要同步 排除  ,也可通过控制 cols属性来隐藏、显示
  			contents.push(btds[i].innerText);
  			if(j == 0){  //只跑一圈
  				widthArr.push({wpx:btds[i].scrollWidth});
  			}
//			}
  	}
  	bodysArr.push(contents)
  }
  var styleCell = {
  	font: {  // 定义样式 居中,背景色,字体大小,边框
  		name:'宋体',
          sz: 14,
          bold: true,
          family:1
          
        },
      fill:{
      	bgColor: {
      		rgb: 'FFfd9a80'    // 没有效果,不知道哪里除了问题
      	}
      	,
      	fgColor: { // 背景颜色
      		rgb:'94fba7'
      	}
      },
      alignment: {
        	vertical: 'center'
          ,horizontal: 'center'
//            ,wrapText: true
        }
      ,border:{
        	top: {
  		    style: 'thin'
  		  },
  		bottom: {
  		    style: 'thin'
  		  },
  		left: {
  		    style: 'thin'
  		  },
  		right: {
  		    style: 'thin'
  		  }
        }
  	};
  var sheet = XLSX.utils.aoa_to_sheet(bodysArr);
  for(var item in sheet){  // 遍历sheet 对象,给需要的对象 添加样式
  	let aa = sheet[item];
  	let rindex =  item.replace(/[^0-9]/ig,"");  // excel 行下标
//		let cindex =  item.replace(/[^0-9]/ig,"");  // excel 列下标
  	if(rindex <= htrs.length){  // 判断是不是 表头
  		aa.s = styleCell;  // 样式设置
  	}else{ // 数据内容 样式
  		
  	}
  }
  
  sheet['!merges'] = mergeArr;
  sheet['!rows'] = [{hpx:30},{hpx:28}]; // 设置行高
  sheet['!cols'] = widthArr;
  
  openDownloadDialog(sheet2blob(sheet), '高新课题历史数据导出'+new Date().toLocaleString()+'.xlsx');
}

4. 封装之后的sheet

在这里插入图片描述

!cols

在这里插入图片描述

!rows

在这里插入图片描述

! merges

在这里插入图片描述

5. 样式文档

参数参数子参数
fillpatternType“solid” or “none””
fgColorCOLOR_SPEC --背景颜色
bgColorCOLOR_SPEC ?
fontname“Calibri” // default
sz“11” // font size in points
colorCOLOR_SPEC
boldtrue or false
underlinetrue or false
italictrue or false
striketrue or false
outlinetrue or false
shadowtrue or false
vertAligntrue or false
numFmt“0” // integer index to built in formats, see StyleBuilder.SSF property
“0.00%” // string matching a built-in format, see StyleBuilder.SSF
“0.0%” // string specifying a custom format
“0.00%;(0.00%);-;@” // string specifying a custom format, escaping special characters
“m/dd/yy” // string a date format using Excel’s format notation
alignmentvertical“bottom” or “center” or “top”
horizontal“bottom” or “center” or “top”
wrapTexttrue or false
readingOrder2 // for right-to-left
textRotationNumber from 0 to 180 or 255 (default is 0)
90 is rotated up 90 degrees
45 is rotated up 45 degrees
135 is rotated down 45 degrees
180 is rotated down 180 degrees
255 is special, aligned vertically
bordertop{ style: BORDER_STYLE, color: COLOR_SPEC }
bottom{ style: BORDER_STYLE, color: COLOR_SPEC }
left{ style: BORDER_STYLE, color: COLOR_SPEC }
right{ style: BORDER_STYLE, color: COLOR_SPEC }
diagonal{ style: BORDER_STYLE, color: COLOR_SPEC }
diagonalUptrue or false
diagonalDowntrue or false

COLOR_SPEC: 填充、字体和边框的颜色对象:
       { auto: 1}指定自动值
       { rgb: “FF4dAA00” } 指定16进制的ARGB // rgb:“4dAA00” ,会自动添加FF变成 FF4dAA00
       { theme: “1”, tint: “-0.25”} 指定主题颜色和色调的整数索引(默认值为0)
       { indexed: 64} 默认值 fill.bgColor

BORDER_STYLE: 边框样式是一个字符串值,它可以是以下值之一:
       thin
       medium
       thick
       dotted
       hair
       dashed
       mediumDashed
       dashDot
       mediumDashDot
       dashDotDot
       mediumDashDotDot
       slantDashDot

3.参考文献

https://www.cnblogs.com/liuxianan/p/js-excel.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值