Handsontable 表头的合并、导出、小计合计等设置,内含github实例以及包连接
·
背景:vue项目中使用了handsontable做报表,表格比较复杂。后端返回表格数据,在前端整理成handsontable需要的数据格式后展示。涉及到了查询、根绝查询结果动态渲染表头、导出等功能。
因为当时搞了好久,所以这里详细记录下遇到的问题。
写了一个handsontable的小demo放在github上了 【传送门】,包含以上功能,项目启动后的访问地址:http://localhost:8080/#/hotTableComp
。
handson介绍
handsontable引用方式:cdn or npm or 访问本地静态文件
(当时由于项目打包的原因,打包后静态文件访问不到,所以就直接将handsontable.full.min.js和xlsx.core.min.js的包放在的服务器上,然后在index.html直接引用服务器上的地址,相当于挂在window对象中,在组件里就可以直接从window上取到使用了)。
- cdn引用的方式,放在index.html文件中全局引入:
<script src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.2/xlsx.core.min.js"></script>
- 本地静态文件可以在Github上找到
- npm安装的使用和前两种不同,还没有进行尝试,尝试之后更新
Handsontable配置说明
目录结构如下:
- HandsonTable.js
组件初始化时,实例化Handsontable
/**
* @description 生成报表,参数由父组件传入;
* @param {object} dataSource; 表格渲染的数据源;
* @param {array} columns 列定义;
* @param {array} colHeaders 表格头标签; 如果有合并表头的需求,失效,使用 nestedHeaders;
* @param {array} nestedHeaders 合并表头时配置对象;
* @param {array} mergeCells 合并行标题配置对象;
*/
renderDashboard(
dataSource,
columns,
nestedHeaders,
mergeCells,
columnSummaryList
) {
var hotElement = document.getElementById("handsonContainer");
var hotElementContainer = hotElement.parentNode;
// 设置setting对象;
let hotSettings = JSON.parse(JSON.stringify(this.defaultSettings));
hotSettings.data = dataSource;
hotSettings.columns = columns;
hotSettings.mergeCells = mergeCells;
hotSettings.nestedHeaders = nestedHeaders;
hotSettings.columnSummary = columnSummaryList;
hotSettings.readOnly = true;
hotSettings.exportFile = true;
hotSettings.rowHeaders = true;
hotSettings.contextMenu = true;
// 合并setting对象的个性化参数;
if (!!this.customSettings) {
hotSettings = Object.assign(hotSettings, this.customSettings);
}
// 初始化实例;
var hot = new Handsontable(hotElement, hotSettings);
}
data中的默认设置:
defaultSettings: {
licenseKey: "non-commercial-and-evaluation",
stretchH: "all",
width: "100%",
autoWrapRow: true,
height: 400,
maxRows: 14,
rowHeaders: true,
columnSorting: false, //排序属性;
// colHeaders: colHeaders || [],
colWidths: 80,
className: "htRight htMiddle",
data: [],
mergeCells: [],
columns: [],
nestedHeaders: [],
columnSummary: []
},
- hotTable.js
nestedHeaders
:
数组。实现自定义表头、合并表头等。
要算好表格一共多少列,表头一共多少行。以第一张图片的为例,17列,4行。那么nestedHeaders数组应该长度为4,每一个元素中colspan和应为17:
// 合并表头;
nestedHeaders: [
//第一行
[
{
label: "2019年 9月 30日",
colspan: 12
},
{
label: "单位:万元",
colspan: 4
}
],
//第二行
[
"",
"",
{
label: "保险板块",
colspan: 6
},
{
label: "其中:代理费",
colspan: 4
},
{
label: "其中:经纪费",
colspan: 4
}
],
//第三行
[
"",
"",
{
label: "本月",
colspan: 3
},
{
label: "本年",
colspan: 3
},
{
label: "本月",
colspan: 2
},
{
label: "本年",
colspan: 2
},
{
label: "本月",
colspan: 2
},
{
label: "本年",
colspan: 2
},
{
label: "本月",
colspan: 2
},
{
label: "本年",
colspan: 2
}
],
//第四行
[
"险类",
"险种名称",
"保费",
"同比增长值",
"同比增长率",
"保费",
"同比增长值",
"同比增长率",
"保费",
"同比增长值",
"保费",
"同比增长值",
"保费",
"同比增长值",
"保费",
"同比增长值"
]
],
columns
:
每列对应字段,因为第一列是序号,所以一共写16列。
即columns为长度16的数组。
// 定义列;
columns: [
{
data: "ensureType",
type: "text",
width: 50,
className: "htCenter htMiddle"
},
{
data: "ensureName",
type: "text",
width: 110,
className: "htCenter htMiddle"
},
{
data: "monthFee",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "monthIncreaseNum",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "monthIncreaseRadio",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "yearFee",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "yearIncreaseNum",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "yearIncreaseRadio",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "agencyMonthFee",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "agencyMonthIncreaseNum",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "agencyYearFee",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "agencyYearIncreaseNum",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "manageMonthFee",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "manageMonthIncreaseNum",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "manageYearFee",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
},
{
data: "manageYearIncreaseNum",
type: "numeric",
numericFormat: {
pattern: "0.00"
}
}
],
columnSummaryList
:
合计数据的配置对象集合,即进行行计算。例如(按序列来看)第1、2、5、6、7、8行相加为第9行,10、11、12行相加为第13行,9、13相加为第14行。(实际行数从0开始)
/**
* @param 获取需要计算单元格配置;
*/
getColumnSummary() {
let retSummaryCfg = [];
let columnList = [2, 3, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15]; // 需要计算的列的索引的集合,从0开始算;
for (var i = 0; i < columnList.length; i++) {
var tempCfg1 = {
destinationRow: 8, //求和后存放“和”的行
destinationColumn: columnList[i], //目标的合并列
type: "sum",
forceNumeric: true,
ranges: [
[0, 1], //被相加的行,相邻的可以放在一个数组中
[4, 7] //被相加的行
]
};
retSummaryCfg.push(tempCfg1);
var tempCfg2 = {
destinationRow: 12,
destinationColumn: columnList[i],
type: "sum",
forceNumeric: true,
ranges: [[9, 11]]
};
retSummaryCfg.push(tempCfg2);
var tempCfg3 = {
destinationRow: 13,
destinationColumn: columnList[i],
type: "sum",
forceNumeric: true,
ranges: [
[0, 1],
[4, 7],
[9, 11]
]
};
retSummaryCfg.push(tempCfg3);
}
return retSummaryCfg; //最终返回合并的行的对象
}
- exportTable.js
导出表头
:
由于直接导出当前表格时,表头无法导出,导出的是表格的内容部分,所以要在导出之前追加一个要导出的表头,格式如下:
第一部分:写出表头汉字对应的内容,将要被合并的单元格置空。A1
代表第1行A列对应的单元格,H4
代表4行H列对应的单元格;
第二部分:"!merges"
接受一个数组,每个元素是要合并的单元格对象,例如:表头第一个要合并的是“2019年9月30日”那个单元格,那么应传入{ s: { c: 0, r: 0 }, e: { c: 11, r: 0 } }
,表示从0行0列开始,到0行11列结束。
head: {
//第一部分
A1: { v: "2019年 9月 30日" },
B1: { v: "" },
C1: { v: "" },
D1: { v: "" },
E1: { v: "" },
F1: { v: "" },
G1: { v: "" },
H1: { v: "" },
I1: { v: "" },
J1: { v: "" },
K1: { v: "" },
L1: { v: "" },
M1: { v: "单位:万元" },
N1: { v: "" },
O1: { v: "" },
P1: { v: "" },
A2: { v: "险类" },
B2: { v: "险种名称" },
C2: { v: "保险板块" },
D2: { v: "" },
E2: { v: "" },
F2: { v: "" },
G2: { v: "" },
H2: { v: "" },
I2: { v: "其中:保代" },
J2: { v: "" },
K2: { v: "" },
L2: { v: "" },
M2: { v: "其中:保经" },
N2: { v: "" },
O2: { v: "" },
P2: { v: "" },
A3: { v: "" },
B3: { v: "" },
C3: { v: "本月" },
D3: { v: "" },
E3: { v: "" },
F3: { v: "本年" },
G3: { v: "" },
H3: { v: "" },
I3: { v: "本月" },
J3: { v: "" },
K3: { v: "本年" },
L3: { v: "" },
M3: { v: "本月" },
N3: { v: "" },
O3: { v: "本年" },
P3: { v: "" },
A4: { v: "" },
B4: { v: "" },
C4: { v: "保费" },
D4: { v: "同比增长值" },
E4: { v: "同比增长率" },
F4: { v: "保费" },
G4: { v: "同比增长值" },
H4: { v: "同比增长率" },
I4: { v: "保费" },
J4: { v: "同比增长值" },
K4: { v: "保费" },
L4: { v: "同比增长值" },
M4: { v: "保费" },
N4: { v: "同比增长值" },
O4: { v: "保费" },
P4: { v: "同比增长值" },
//第二部分
"!merges": [
// s: start e: end c: col r: row
{ s: { c: 0, r: 0 }, e: { c: 11, r: 0 } },
{ s: { c: 12, r: 0 }, e: { c: 15, r: 0 } },
{ s: { c: 0, r: 1 }, e: { c: 0, r: 3 } },
{ s: { c: 1, r: 1 }, e: { c: 1, r: 3 } },
{ s: { c: 2, r: 1 }, e: { c: 7, r: 1 } },
{ s: { c: 8, r: 1 }, e: { c: 11, r: 1 } },
{ s: { c: 12, r: 1 }, e: { c: 15, r: 1 } },
{ s: { c: 2, r: 2 }, e: { c: 4, r: 2 } },
{ s: { c: 5, r: 2 }, e: { c: 7, r: 2 } },
{ s: { c: 8, r: 2 }, e: { c: 9, r: 2 } },
{ s: { c: 10, r: 2 }, e: { c: 11, r: 2 } },
{ s: { c: 12, r: 2 }, e: { c: 13, r: 2 } },
{ s: { c: 14, r: 2 }, e: { c: 15, r: 2 } },
{ s: { c: 0, r: 4 }, e: { c: 0, r: 12 } },
{ s: { c: 0, r: 13 }, e: { c: 0, r: 15 } },
{ s: { c: 0, r: 16 }, e: { c: 1, r: 16 } },
{ s: { c: 0, r: 17 }, e: { c: 1, r: 17 } }
]
},
导出方法
:
这里用到了XLSX插件,xlsxUtils
上面挂载了插件的方法。
//导出按钮触发
/*
* @param {String} 默认显示的日期
*/
exportFun(date) {
var wopts = { bookType: "xlsx", bookSST: false, type: "binary" };
this.downloadExl(date);
},
downloadExl(date) {
var data = xlsxUtils.format2Sheet(
this.dataSource,
0,
this.rowHeaderNum,
this.keyMap
); //偏移2行按keyMap顺序转换
var dataKeys = Object.keys(data);
for (var k in this.exportHead) {
data[k] = this.exportHead[k]; //追加列头
}
data.A1.v = date.slice(0, 7);
var wb = xlsxUtils.format2WB(
data,
undefined,
undefined,
"A1:" + dataKeys[dataKeys.length - 1]
);
this.saveAs(xlsxUtils.format2Blob(wb), `${this.tableTitle}.xlsx`);
},
saveAs(obj, fileName) {
var tmpa = document.createElement("a");
tmpa.download = fileName || "下载";
tmpa.href = URL.createObjectURL(obj); //绑定a标签
tmpa.click(); //模拟点击实现下载
setTimeout(function() {
//延时释放
URL.revokeObjectURL(obj); //用URL.revokeObjectURL()来释放这个object URL
}, 100);
}
最后
项目中也能找到这以下文件:
handsontable.full.min.js
xlsx.core.min.js
handsontable.js
xlsx.utils.min.js
Blob.js
Export2Excel.js
官网demo传送门,实例了一个Handontable对象。
更多推荐
已为社区贡献2条内容
所有评论(0)