Vue用Export2Excel匯出excel,多級表頭資料
阿新 • • 發佈:2021-11-10
最近公司前端做一個匯出資料到Excel表單,並要求有表頭,做了下簡單樣式修改,但是xlsx檔案單元格高度沒有生效,記錄一下,希望能別人一些幫助。
1.安裝依賴 四個安裝包
npm install --save file-saver
npm install --save xlsx
npm install -D script-loader
npm install --save xlsx-style
2.建立檔案
在專案src 下建立util資料夾
然後建立Export2Excel.js檔案
/* eslint-disable */ import { saveAs } from 'file-saver' // import XLSX from 'xlsx' import XLSX from "xlsx-style" // require('script-loader!file-saver'); // import XLSX from 'xlsx-style' function generateArray(table) { var out = []; var rows = table.querySelectorAll('tr'); var ranges = []; for (var R = 0; R < rows.length; ++R) { var outRow = []; var row = rows[R]; var columns = row.querySelectorAll('td'); for (var C = 0; C < columns.length; ++C) { var cell = columns[C]; var colspan = cell.getAttribute('colspan'); var rowspan = cell.getAttribute('rowspan'); var cellValue = cell.innerText; if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue; //Skip ranges ranges.forEach(function (range) { if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) { for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null); } }); //Handle Row Span if (rowspan || colspan) { rowspan = rowspan || 1; colspan = colspan || 1; ranges.push({ s: { r: R, c: outRow.length }, e: { r: R + rowspan - 1, c: outRow.length + colspan - 1 } }); }; //Handle Value outRow.push(cellValue !== "" ? cellValue : null); //Handle Colspan if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null); } out.push(outRow); } return [out, ranges]; }; function datenum(v, date1904) { if (date1904) v += 1462; var epoch = Date.parse(v); return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); } function sheet_from_array_of_arrays(data, opts) { var ws = {}; var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } }; for (var R = 0; R != data.length; ++R) { for (var C = 0; C != data[R].length; ++C) { if (range.s.r > R) range.s.r = R; if (range.s.c > C) range.s.c = C; if (range.e.r < R) range.e.r = R; if (range.e.c < C) range.e.c = C; var cell = { v: data[R][C] }; if (cell.v == null) continue; var cell_ref = XLSX.utils.encode_cell({ c: C, r: R }); if (typeof cell.v === 'number') cell.t = 'n'; else if (typeof cell.v === 'boolean') cell.t = 'b'; else if (cell.v instanceof Date) { cell.t = 'n'; cell.z = XLSX.SSF._table[14]; cell.v = datenum(cell.v); } else cell.t = 's'; ws[cell_ref] = cell; } } if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range); return ws; } function Workbook() { if (!(this instanceof Workbook)) return new Workbook(); this.SheetNames = []; this.Sheets = {}; } function 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; } export function export_table_to_excel(id) { var theTable = document.getElementById(id); var oo = generateArray(theTable); var ranges = oo[1]; /* original data */ var data = oo[0]; var ws_name = "SheetJS"; var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); /* add ranges to worksheet */ // ws['!cols'] = ['apple', 'banan']; ws['!merges'] = ranges; /* add worksheet to workbook */ wb.SheetNames.push(ws_name); wb.Sheets[ws_name] = ws; var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' }); saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), "test.xlsx") } export function export_json_to_excel({ multiHeader = [], header, data, filename, merges = [], autoWidth = true, bookType = 'xlsx', } = {}) { /* original data */ filename = filename || 'excel-list' data = [...data] data.unshift(header); for (let i = multiHeader.length - 1; i > -1; i--) { data.unshift(multiHeader[i]) } var ws_name = "SheetJS"; var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); if (merges.length > 0) { if (!ws['!merges']) ws['!merges'] = []; merges.forEach(item => { ws['!merges'].push(XLSX.utils.decode_range(item)) }) } if (autoWidth) { /*設定worksheet每列的最大寬度*/ const colWidth = data.map(row => row.map(val => { /*先判斷是否為null/undefined*/ if (val == null) { return { 'wch': 10 }; } /*再判斷是否為中文*/ else if (val.toString().charCodeAt(0) > 255) { return { 'wch': val.toString().length * 2.5 }; console.log('111111') } else { console.log('22222') return { 'wch': val.toString().length * 1.5 }; } })) // onsole.log(colWidth); /*以第一行為初始值*/ colWidth[0][0] = colWidth[0][1]; let result = colWidth[0]; console.log(result) for (let i = 1; i < colWidth.length; i++) { for (let j = 0; j < colWidth[i].length; j++) { if (result[j]['wch'] < colWidth[i][j]['wch']) { result[j]['wch'] = colWidth[i][j]['wch']; } } } ws['!cols'] = result; //設定高 // wb['!rows'] = [{ hpx:200 }]; const colHeight = data.map(row => row.map(val => { /*先判斷是否為null/undefined*/ if (val == null) { return { 'hpx': 40 }; } /*再判斷是否為中文*/ else if (val.toString().charCodeAt(0) > 255) { return { 'hpx': 400 }; } else { return { 'hpx': 400 }; } })) // console.log(colHeight) /*以第一行為初始值*/ let result1 = colHeight[0]; for (let i = 1; i < colHeight.length; i++) { for (let j = 0; j < colHeight[i].length; j++) { if (result1[j]['hpx'] < colHeight[i][j]['hpx']) { result1[j]['hpx'] = colHeight[i][j]['hpx']; } } } ws['!rows'] = result1; } /* add worksheet to workbook */ wb.SheetNames.push(ws_name); wb.Sheets[ws_name] = ws; var dataInfo = wb.Sheets[wb.SheetNames[0]]; // 設定單元格框線 const borderAll = { top: { style: "thin" }, bottom: { style: "thin" }, left: { style: "thin" }, right: { style: "thin" } }; // 給所有單元格加上邊框,內容居中,字型,字號,標題表頭特殊格式部分後面替換 for (var i in dataInfo) { if ( i == "!ref" || i == "!merges" || i == "!cols" || i == "!rows" || i == "A1" ) { } else { dataInfo[i + ""].s = { border: borderAll, alignment: { horizontal: "center", vertical: "center" }, font: { name: "微軟雅黑", sz: 10 } }; } } /** * 自定義 */ var dataInfo = wb.Sheets[wb.SheetNames[0]]; let arr = [ "A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1", "I1", "J1", "K1", "L1", "M1", "N1", "O1", "P1", "Q1", "R1", "S1", "T1", "U1", "V1", "W1", "X1", "Y1", "Z1" ]; let style = { font: { color: { rgb: "ffffff" }, bold: true }, alignment: { horizontal: "center", vertical: "center" }, //單元格背景色 fill: { fgColor: { rgb: "8CB3E4" }, }, }; for (var i = 0; i < header.length; i++) { dataInfo[arr[i]].s = style; } var wbout = XLSX.write(wb, { bookType: bookType, bookSST: false, type: 'binary' }); saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), `${filename}.${bookType}`); }
3.vue中呼叫
把匯出功能寫成了個方法
// 匯出多個個表頭 handleDownload() { import("../../util/Export2Excel.js").then((excel) => { const multiHeader = [ [this.tempTitle, "", "", "", "", "", "", "", "", ""], ]; // 表頭資料 const header = [ "序號", "部門", "姓名", "部門正副職平均分", "權重", "職工代表", "權重", "總分", "部門內部排名", "備註", ]; // 資料來源中,代替表頭的變數 const filterVal = [ "fare", "sheng", "name", "lenglian", "lenglian", "inforadio", "fare", "phone", "fare", "fare", ]; const merges = ["A1:J1"]; // 資料來源 const list = this.tableData; // 拼接資料 const data = this.formatJson(filterVal, list); // const data = []; excel.export_json_to_excel({ multiHeader, header, data, // 匯出表格的檔名字 filename: this.tempTitle, merges, }); }); }, // 拼接資料 formatJson(filterVal, jsonData) { return jsonData.map((v) => filterVal.map((j) => { return v[j]; }) ); },
效果如下:
可能遇到的問題
解決方案1: 修改為 var cpt = cptable 修改的只是本地檔案
解決方案2:webpack.base.conf.js
module.exports = {undefined
externals: [ {undefined
'./cptable': 'var cptable'
}]
}