前言
最近项目需要导出附带样式的excel表,发现xlsx根本不够用,索性当起了cv工程师寻找大佬们的xlsx-style方法。最终参考了一个封装的很容易懂的方法,记录了自己的学习和理解,留作自己的学习笔记和未来工作参考。
此文针对于通过数据源生成excel,并非基于table组件生成样式表
xlsx-style 使用的wb对象
- npm install xlsx-style
- \node_modules\xlsx-style\dist\cpexcel.js 807行的var cpt = require(‘./cpt’ + ‘able’);更换成var cpt = cptable;
遇到看不懂的就直接console.log(wb)
可以看出
一个wb其实就是将Excel工作表下面的sheet的内容拆分进入了Sheets属性,将工作表sheet的名称归入了SheetNames属性
(所以最开始接触xlsx的时候搞不懂为啥会有类似于wb.Sheets[wb.SheetNames[index]]这么复杂的写法。。)
对于大部分的格式操作,都是处理Sheets子对象的各类属性:
总而言之,要做的就是把要生成的数据,塞进一个叫做wb的对象(Workbook Obejct)的Sheets 对象(Sheet Object)里面去, 同时附带了一些样式属性,以便于导出的时候系统知道我们想加哪些样式
源码和地址及其补充说明
贴一下大佬的原封装
https://juejin.cn/post/7099056841962815502
总体来说,大佬就是封装了一个带有样式的数据源(数组),一个样式合集(对象),一个数据归入(将需要导出的数据通过Object.Assign的方法创造了上述提到的Sheets子对象-> 计费账单:{})的方法,以及一个将wb对象导出成excel的方法
一个个来看:
封装的数据源(dataSource)是一些数据和样式属性构成。数据没啥好说的,array之类的构成,处理好对应好表头就出来了
本身自带有cellStyle,里面有style对象,建议删掉,大佬的封装有自带的defaultStyle对象,后续有特殊的再修改
workSheetConfig 是考虑到合并单元格和冻结单元,作用于’!merges’ 和!freeze
冻结没用过,待以后有了体会再回来更新
合并单元格很好理解,输入s(start) 和 e(end)的位置,严格塞进一个对象就好了
colWidth 列宽数组,作用于’!cols’
{wpx:200} 固定方式的键值对,随意更改键值
这里塞入一下文档:
ws[‘!cols’]: array of column properties objects. Column widths are actually stored in files in a normalized manner, measured in terms of the “Maximum Digit Width” (the largest width of the rendered digits 0-9, in pixels). When parsed, the column objects store the pixel width in the wpx field, character width in the wch field, and the maximum digit width in the MDW field.
ws[‘!merges’]: array of range objects corresponding to the merged cells in the worksheet. Plain text formats do not support merge cells. CSV export will write all cells in the merge range if they exist, so be sure that only the first cell (upper-left) in the range is set.
文档没有这些属性咋用的实例(可能我没找到),其实通俗来说就是将上述的sheet对象里面塞我需要的东西就行。
需要合并哪些,就找到这个Sheet1(计费账单)塞进去,需要哪些列宽指定好,就把列宽数组塞进去
// An highlighted block
wb.Sheets.['计费账单']['!merges'] = [...merges]
wb.Shhets.['计费账单']['!cols'] = [...colWidth]
因此大佬就通过这种原理构建了每个sheet。后续自己用的时候需要注意,每个sheet如果有不同的处理方法,在
// An highlighted block
exportData.forEach (data,index)=>{}
这里区分开来。
生成excel文件导出,这里大佬写的很详细,自行观看
独立样式修改
总会有个别地方需要自己手动修改样式,比如一些奇怪的表
需要修改这些个别的东西时候,按照上述提到的方法,改就完了!
注意点:
- 单元格所有属性严格按规定来,介绍下单元格的所有属性
V: 表示单元格的值;value
t:表示单元格值的类型,b:表示Boolean布尔值,n表示number数组,e表示error错误信息,s表示string字符串,d:表示date日期; tyle
s: 表示单元格的样式. style
而style本身的属性很多,也必须固定好:
alignment: {vertical: ‘’, horizontal: ‘’, wrapText: } 对齐与换行
border: {top: {…}, bottom: {…}, left: {…}, right: {…}} 四周边框
fill: {fgColor: {…}, bgColor: {…}} 填充色
font: {name: ‘宋体’, sz: 12, italic: false, underline: false, bold: true} 字体 - 修改单元格对象的样式的时候要一次修改整个s(style),而不能修改s对象里面的属性
曾经通过wb.Sheets[wb.SheetNames[index]][‘A4’].s.font.bold 企图修改一个加粗,结果发现全文加粗,晕了,只能老老实实修改s属性 - 修改的时候注意前后可能会覆盖
小问题,自己要注意是不是先修改了加粗,后修改了字体大小之类的问题…
贴一下部分源码和结构:
// An highlighted block
borderAll = {
top: {
style: 'thin'
},
bottom: {
style: 'thin'
},
left: {
style: 'thin'
},
right: {
style: 'thin'
}
}
// 单个单元格操作
// index是当前的sheet,0,1,2...
wb.Sheets[wb.SheetNames[index]].A4.s = {
border: borderAll, // 默认边框
font: { name: '宋体', sz: 12, italic: false, underline: false, bold: true}, // 加粗等..
alignment: { vertical: 'center', horizontal: 'center', wrapText: true }, // 对齐...
fill: { fgColor: { rgb: 'd9d9d9' } } //填充背景色..
}
// 多单元格操作
boldArray= ['A1','A2','A3','B1','B2']
boldArrayStyle = {
border: borderAll, // 默认边框
font: { name: '宋体', sz: 12, italic: false, underline: false, bold: true}, // 加粗等..
alignment: { vertical: 'center', horizontal: 'center', wrapText: true }, // 对齐...
fill: { fgColor: { rgb: 'd9d9d9' } } //填充背景色..
}
for(let item in wb.Sheets[wb.SheetNames[index]]) {
if(boldArray.includes(item)) {
wb.Sheets[wb.SheetNames[index]][item].s = boldArrayStyle
// console.log(item, wb.Sheets[wb.SheetNames[index]][item].s.font.bold);
}
}
总结
这个封装下的xlsx-style没有提到行高,因为目前业务也没涉及,就没有按照网上的教程去修改xlsx-style源码。
同时基于这次的学习,还完成了一些el-table生成excel并附带一些注释和简单样式的临时方法,原理也是操作wb对象或者操作table node。
以后有也会再更新笔记。
之前一直读英文文档却没有实例,看得懂却不会写,愣在原地不知道怎么搞一个符合标准的对象。大佬的封装让我半天就搞明白这个东西到底怎么弄的,并且很容易就看明白wb,sheet的结构。再次感谢各位大神