因爲項目臨時加入導出Excel功能,後臺童靴沒有多餘時間來處理,想前端來處理導出。前端
查詢了前端導出方法,大部分是利用js-xlsx
來作處理,按照js-xlsx來導出excel
時是沒有樣式處理的。須要咱們來利用該庫的專業版本才能設置樣式。git
這裏就須要xlsx-style來處理,給咱們的excel
文件來添加樣式。github
拿到後端數據,先要對數據進行組裝才能導出咱們想要的文件格式。若是想文件有樣式只能利用xlsx-style
;npm
npm install xlsx-style
拷貝下載下來的文件目錄dist
裏的xlsx.core.min.js
,引入文件後端
這裏借鑑這位博主主要代碼,整理了下,能夠實現表頭與導出文件名稱。dom
具體調用能夠查看DEMOthis
/** * @param {Array} header 表格頭部 * @param {Array} body 表格數據 * @param {String} title 表格導出名稱 * @param {Boolean} hasTitle 是否須要表格標題 */ function ExportsEXCL() { this.downLoad = ({ header = [], body = [], title = 'excel', hasTitle = false, }) => { const styleCell = this.setBorderStyle(); const _headers = header .map((v, i) => { let key = Object.keys(v); return Object.assign( {}, { v: `${v[key[0]]}<key>${key[0]}`, position: String.fromCharCode(65 + i) + (hasTitle ? 1 : 0) } ); }) .reduce( (prev, next) => Object.assign({}, prev, { [next.position]: { v: next.v, s: styleCell } }), {} ); const _body = body .map((v, i) => header.map((k, j) => { let key = Object.keys(k); return Object.assign( {}, { v: v[key[0]], position: String.fromCharCode(65 + j) + (i + (hasTitle ? 2 : 1)) } ); }) ) .reduce((prev, next) => prev.concat(next)) .reduce( (prev, next) => Object.assign({}, prev, { [next.position]: { v: next.v, s: styleCell } }), {} ); const mergeThead = this.setMergeThead(_headers, hasTitle, title); const _merges = this.setTableMerges(header, _headers, hasTitle); const _thead = this.setTableThead(mergeThead); const output = Object.assign({}, _thead, _body); const outputPos = Object.keys(output).sort(); const ref = outputPos[0] + ':' + outputPos[outputPos.length - 1]; const wb = { SheetNames: ['mySheet'], Sheets: { mySheet: Object.assign({}, output, { '!ref': ref, '!merges': _merges }) } }; this.save(wb, `${title}.xlsx`); }; this.setTableThead = wb => { for (let key in wb) { let i = wb[key].v.indexOf('<key>'); if (wb[key].v.includes('<key>')) { wb[key].v = wb[key].v.substr(0, i); } } return wb; }; // 設置合併表頭 this.setTableMerges = (header, wb, hasTitle) => { let _merges = []; let len = header.length - 1; if (hasTitle) { let o = { s: { c: 0, r: 0 }, e: { c: len, r: 0 } }; _merges.push(o); } return [..._merges]; }; // 設置表頭 this.setMergeThead = (wb, merge, hasTitle, title) => { const borderAll = { top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } }; if (hasTitle) { wb['A1'] = { v: `${title}`, s: { border: borderAll, font: { sz: 18, bold: true }, alignment: { horizontal: 'center' } } }; } return wb; }; this.setBorderStyle = () => { const borderAll = { top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } }; return { border: borderAll }; }; this.save = (wb, fileName) => { let wopts = { bookType: 'xlsx', bookSST: false, type: 'binary' }; let xw = XLSX.write(wb, wopts); let obj = new Blob([this.s2ab(xw)], { type: '' }); let elem = document.createElement('a'); elem.download = fileName || '下載'; elem.href = URL.createObjectURL(obj); elem.click(); setTimeout(function() { URL.revokeObjectURL(obj); }, 100); }; this.s2ab = s => { if (typeof ArrayBuffer !== 'undefined') { 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; } else { var buf = new Array(s.length); for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff; return buf; } }; // 根據val查詢Object key this.findKey = (val, obj) => { return Object.keys(obj).find(v => obj[v] === val); }; }
js-xlsx
提供了一個直接導出HTML上的DOM表格方法XLSX.utils.table_to_book
,可是導出的excel
文件時沒有任何樣式,利用xlsx-style
中的xlsx.full.min.js
來導出時,沒有上面這個方法,後面取了巧。spa
把xlsx-style
中的full
文件導出來的XLSX
改爲了STYLEXLSX
;3d
引用以下:excel
<script src="//unpkg.com/xlsx/dist/shim.min.js"></script> <script src="//unpkg.com/blob.js@1.0.1/Blob.js"></script> <script src="//unpkg.com/file-saver@1.3.3/FileSaver.js"></script> <script src="./STYLEXLSX.full.min.js"></script> <script src="./xlsx.full.min.js"></script> <script src="./index.js"></script>
利用js-xlsx
來導出表格數據,用STYLEXLSX.write
來寫入數據。
STYLEXLSX.write( wb, { bookType: type == undefined ? 'xlsx' : type, bookSST: false, type: 'binary' } )
具體主要代碼:
/** * * @param {Object} dom table的dom元素 * @param {Object} name 導出的表名 * @param {Object} type 導出的類型 * */ function exportExl(dom, name = '導出數據', type) { var wb = XLSX.utils.table_to_book(dom, {sheet: "Sheet JS"}); var wopts = { bookType: 'xlsx', bookSST: true, type: 'binary', cellStyles: true }; setExlStyle(wb['Sheets']['Sheet JS']); let tmpDown = new Blob( [ this.s2ab( STYLEXLSX.write( wb, { bookType: type == undefined ? 'xlsx' : type, bookSST: false, type: 'binary' } //這裏的數據是用來定義導出的格式類型 ) ) ], { type: '' } ); saveAs( tmpDown, `${name}` + '.' + (wopts.bookType == 'biff2' ? 'xls' : wopts.bookType) ); } function saveAs(obj, fileName) { let tmpa = document.createElement('a'); tmpa.download = fileName || '下載'; tmpa.href = URL.createObjectURL(obj); tmpa.click(); setTimeout(function() { URL.revokeObjectURL(obj); }, 100); } function s2ab (s){ if (typeof ArrayBuffer !== 'undefined') { 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; } else { var buf = new Array(s.length); for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff; return buf; } }; function setExlStyle (data) { let borderAll = { //單元格外側框線 top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } }; data['!cols'] = []; for (let key in data) { if (data[key] instanceof Object) { data[key].s = { border: borderAll, alignment: { horizontal: 'center' //水平居中對其 }, numFmt: 0 } data['!cols'].push({wpx: 170}); } } return data; }
若是用數據來控制咱們的導出,發現配置多級表頭時會好複雜,因此沒去深究了,用DOM來導出,又發現若是要導出分頁表格時只能導出當前頁的數據。
並且如今全部的表格均可能不是規範的表格,每一個表格結構可能都不相同,只能單獨處理。
當前全部代碼查看