网站上线流程分为seo职位要求
vue项目+xlsx+xlsx-style 实现table导出为excel的功能
最近遇到一个需求,后端提供一组数据,根据这组数据,导出为一个excel表格。
步骤如下:
1. 导出内容的预览如下:包含单元格的合并等操作。
2. 点击右下角导出按钮,可以直接下载一个excel表格。
由于我之前有用过csdn版本的xlsx-style
,因此首先想到的就是使用xlsx
来实现此功能。
下面介绍详细步骤:
1.安装xlsx
和xlsx-style
依次安装以下的内容:
npm install xlsx --save
npm install xlsx-style --save
2.局部注册使用
由于我这边是单个页面使用此功能,因此并没有在main.js
中全局注册
局部注册的方法:
import * as XLSX from 'xlsx';
import * as XLSX2 from 'xlsx-style';
注意:一定要重命名其中的方法,就是用as 重命名,因为两个插件导出的名字默认都叫XLSX,如果不进行重命名,则会报错
3. vue.config.js
中需要添加以下配置
如果不添加下面的代码,则运行时,代码会报错。
config.externals = {'./cptable': 'var cptable',
};
4.html
预览用table
组件来实现(VUE)
我对上面的表格进行了拆分,一个table
里面包含了4组<thead></thead><tbody></tbody>
。
合并单元格 我使用的是colspan="n"
<table border="1" width="100%" cellspacing="0" cellpadding="0" id="tableId"><thead><tr><th colspan="7" class="headerCls">{{ info.saleOrderCode }}采购需求清单</th></tr></thead><tbody><tr><td>计划套数</td><td colspan="2">{{ info.producePlansCount }}</td><td>付款时间</td><td colspan="3">{{ info.lastPaidTime }}</td></tr><tr><td>申请时间</td><td colspan="2">{{ info.applicantTime }}</td><td>申请人员</td><td colspan="3">{{ info.applicantName }}</td></tr><tr><td>计划交期</td><td colspan="2">{{ info.deliveryTime }}</td><td>打印时间</td><td colspan="3">{{ info.printTime }}</td></tr></tbody><thead><tr><th colspan="5" class="leftTitCls">板材需求明细</th><th>板材系数</th><th>1.2</th></tr></thead><tbody><tr><td>序号</td><td>物品名称</td><td>型号规格</td><td>数量</td><td>单位</td><td>到货时间</td><td>备注</td></tr><tr v-for="(item, index) in list1" :key="item.materialName"><td>{{ index + 1 }}</td><td>{{ item.materialName }}</td><td>{{ item.specification }}</td><td>{{ item.procurementCount }}</td><td>{{ item.unit }}</td><td>{{ item.arrivalTime }}</td><td>{{ item.remark }}</td></tr></tbody><thead><tr><th colspan="5" class="leftTitCls">塑粉需求明细</th><th>喷涂系数</th><th>0.8</th></tr></thead><tbody><tr><td>序号</td><td>物品名称</td><td>型号规格</td><td>数量</td><td>单位</td><td>到货时间</td><td>备注</td></tr><tr v-for="(item, index) in list2" :key="item.materialName"><td>{{ index + 1 }}</td><td>{{ item.materialName }}</td><td>{{ item.specification }}</td><td>{{ item.procurementCount }}</td><td>{{ item.unit }}</td><td>{{ item.arrivalTime }}</td><td>{{ item.remark }}</td></tr></tbody><thead><tr><th colspan="7" class="leftTitCls">外购件需求明细</th></tr></thead><tbody><tr><td>序号</td><td>物品名称</td><td>型号规格</td><td>数量</td><td>单位</td><td>到货时间</td><td>备注</td></tr><tr v-for="(item, index) in list3" :key="item.materialName"><td>{{ index + 1 }}</td><td>{{ item.materialName }}</td><td>{{ item.specification }}</td><td>{{ item.procurementCount }}</td><td>{{ item.unit }}</td><td>{{ item.arrivalTime }}</td><td>{{ item.remark }}</td></tr></tbody></table>
5.导出功能(!!!重要)
数据渲染是通过数组遍历的。
//获取当前时间,用于命名excel表格
let time = this.moment(new Date()).format('YYYY-MM-DD');
//获取整个表格的行数。三个数组长度+其他固定行数(10)
let len = this.list1.length + this.list2.length + this.list3.length + 10;
this.tableToExcel('tableId',`${this.info.saleOrderCode}采购清单需求表${time}`,7,len,1
);
5.1 tableToExcel
方法——入参(表格id,导出文档名称,列数,行数,表头行数)
this.tableToExcel( 'tableId', `采购清单需求表${time}`, 7,len, 1);
tableToExcel(tableId, fileName, headLength, colsLength, headColsLength) {var sheet = XLSX.utils.table_to_sheet(document.querySelector('#' + tableId));//根据tableId获取到元素,通过XLSX.utils.table_to_sheet 获取到sheet表格属性console.log(sheet);//下面是固定写法,可以直接照搬var arr = [];for (let i = 0; i < headLength; i++) {if (i < 26) {arr.push(String.fromCharCode(65 + i).toUpperCase());} else {arr.push('A' + String.fromCharCode(65 + (i - 26)).toUpperCase());}}for (let i = 0; i < arr.length; i++) {//如果是多级表头的话,设置单元格宽度if (headColsLength > 1) {for (let j = 0; j < headColsLength; j++) {if (j < headColsLength && sheet[arr[i] + j]) {if (!sheet[arr[i] + (j + 1)] ||!sheet[arr[i] + (j - 1)] ||(!sheet[arr[i] + (j - 1)] && !sheet[arr[i] + (j + 1)])) {sheet['!cols'].push({wch: sheet[arr[i] + j].v.length * 2 + 3,});}}}} else {//由于我这边是单个表头,因此走这块代码if (!sheet['!cols']) {sheet['!cols'] = [];}//我这边是对 A D E三列要求宽度窄一些,其他的宽一些,主要是根据内容的多少来,也可以根据内容的长度来处理if ((arr[i] + '1').indexOf('A') > -1 ||(arr[i] + '1').indexOf('D') > -1 ||(arr[i] + '1').indexOf('E') > -1) {sheet['!cols'].push({wch: 8,});} else {sheet['!cols'].push({wch: 14,});}}//由于我这边合并单元格后,导致部分边框不展示了,因此通过这个方法来补充边框。sheet = this.addRangeBorder(sheet['!merges'], sheet);//如果仅仅用上面的方法,发现还是有缺失的边框,因此下面又进行了一遍处理。添加边框及其他样式的处理。for (let key in sheet) {if (sheet[key] instanceof Object) {sheet[key].s = {border: {top: {style: 'thin',},bottom: {style: 'thin',},left: {style: 'thin',},right: {style: 'thin',},},alignment: {horizontal: 'center',vertical: 'center',wrap_text: true,},font: {sz: 11,},bold: true,numFmt: 0,};}}}this.downloadExcel(this.sheet2blob(sheet), `${fileName}.xlsx`); //下载},
5.2 解决合并单元格后部分边框消失问题——addRangeBorder
addRangeBorder(range, ws) {// s:起始位置,e:结束位置var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];range.forEach((item) => {var startRowNumber = Number(item.s.r),startColumnNumber = Number(item.s.c),endColumnNumber = Number(item.e.c),endRowNumber = Number(item.e.r);console.log('startColumnNumber',startColumnNumber,endColumnNumber,startRowNumber,endRowNumber);// 合并单元格时会丢失边框样式,例如A1->A4 此时内容在A1 而range内获取到的是从0开始的,所以开始行数要+2for (var i = startColumnNumber; i <= endColumnNumber + 2; i++) {for (var j = startRowNumber; j <= endRowNumber + 2; j++) {if (ws[arr[i] + j]) {ws[arr[i] + j].s = {border: {top: { style: 'thin' },left: { style: 'thin' },bottom: { style: 'thin' },right: { style: 'thin' },},alignment: {horizontal: 'center',vertical: 'center',wrap_text: true,},font: {sz: 11,},bold: true,numFmt: 0,};} else {ws[arr[i] + j] = {s: {border: {top: { style: 'thin' },left: { style: 'thin' },bottom: { style: 'thin' },right: { style: 'thin' },},alignment: {horizontal: 'center',vertical: 'center',wrap_text: true,},font: {sz: 11,},bold: true,numFmt: 0,},t: '',v: '',};}}}});return ws;},
5.3 sheet表格转化为文档流blob
sheet2blob(sheet, sheetName) {sheetName = sheetName || 'sheet1';var workbook = {SheetNames: [sheetName],Sheets: {},};workbook.Sheets[sheetName] = sheet;var wopts = {bookType: 'xlsx',bookSST: false,type: 'binary',};var wbout = XLSX2.write(workbook, wopts);var blob = new Blob([this.s2ab(wbout)], {type: 'application/octet-stream',});return blob;},s2ab(s) {var buf = new ArrayBuffer(s.length);var view = new Uint8Array(buf);for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;return buf;},
5.4 下载excel
文档
downloadExcel(url, saveName) {var blob = new Blob([url], {type: 'application/octet-stream',});var a = document.createElement('a');a.id = 'downloadFtsetBtn';a.style.display = 'none';a.target = '_blank';document.body.appendChild(a);try {var URL = window.URL || window.webkitURL;a.href = URL.createObjectURL(blob);a.download = saveName;if (typeof navigator.msSaveBlob == 'function') {//IEnavigator.msSaveBlob(blob, saveName);}a.click();} catch (e) {console.log(e);}},
完成!!!多多积累,多多收获!!!