vue+elementui 项目纯前端Export2Excel导出excel,并利用xlsx-style设置单元格样式


直接上代码:

需要需要添加的依赖有:

npm install --save xlsx

npm install -S file-saver

npm install -D script-loader

npm install --save xlsx-style(修改表格样式要下载)

Export2Excel.js 这是网上找的插件,做了些许修改

  1 /* eslint-disable */
  2 require('script-loader!file-saver');
  3 require('./Blob.js'); //blob.js也是网上找的,下面会贴上代码
  4 require('script-loader!xlsx/dist/xlsx.core.min');
//注意 直接import xlsx-style会报错,因为npm install xlsx-style 下载下来的依赖 源码有错,需要修改,下面会讲到
5 import XLSX from "xlsx-style" 6 7 function generateArray(table) { 8 var out = []; 9 var rows = table.querySelectorAll('tr'); 10 var ranges = []; 11 for (var R = 0; R < rows.length; ++R) { 12 var outRow = []; 13 var row = rows[R]; 14 var columns = row.querySelectorAll('td'); 15 for (var C = 0; C < columns.length; ++C) { 16 var cell = columns[C]; 17 var colspan = cell.getAttribute('colspan'); 18 var rowspan = cell.getAttribute('rowspan'); 19 var cellValue = cell.innerText; 20 if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue; 21 22 //Skip ranges 23 ranges.forEach(function(range) { 24 if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) { 25 for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null); 26 } 27 }); 28 29 //Handle Row Span 30 if (rowspan || colspan) { 31 rowspan = rowspan || 1; 32 colspan = colspan || 1; 33 ranges.push({ 34 s: { 35 r: R, 36 c: outRow.length 37 }, 38 e: { 39 r: R + rowspan - 1, 40 c: outRow.length + colspan - 1 41 } 42 }); 43 }; 44 45 //Handle Value 46 outRow.push(cellValue !== "" ? cellValue : null); 47 48 //Handle Colspan 49 if (colspan) 50 for (var k = 0; k < colspan - 1; ++k) outRow.push(null); 51 } 52 out.push(outRow); 53 } 54 return [out, ranges]; 55 }; 56 57 function datenum(v, date1904) { 58 if (date1904) v += 1462; 59 var epoch = Date.parse(v); 60 return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); 61 } 62 63 function sheet_from_array_of_arrays(data, opts) { 64 var ws = {}; 65 var range = { 66 s: { 67 c: 10000000, 68 r: 10000000 69 }, 70 e: { 71 c: 0, 72 r: 0 73 } 74 }; 75 for (var R = 0; R != data.length; ++R) { 76 for (var C = 0; C != data[R].length; ++C) { 77 if (range.s.r > R) range.s.r = R; 78 if (range.s.c > C) range.s.c = C; 79 if (range.e.r < R) range.e.r = R; 80 if (range.e.c < C) range.e.c = C; 81 var cell = { 82 v: data[R][C] 83 }; 84 if (cell.v == null) continue; 85 var cell_ref = XLSX.utils.encode_cell({ 86 c: C, 87 r: R 88 }); 89 90 if (typeof cell.v === 'number') cell.t = 'n'; 91 else if (typeof cell.v === 'boolean') cell.t = 'b'; 92 else if (cell.v instanceof Date) { 93 cell.t = 'n'; 94 cell.z = XLSX.SSF._table[14]; 95 cell.v = datenum(cell.v); 96 } else cell.t = 's'; 97 98 ws[cell_ref] = cell; 99 } 100 } 101 if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range); 102 return ws; 103 } 104 105 function Workbook() { 106 if (!(this instanceof Workbook)) return new Workbook(); 107 this.SheetNames = []; 108 this.Sheets = {}; 109 } 110 111 function s2ab(s) { 112 var buf = new ArrayBuffer(s.length); 113 var view = new Uint8Array(buf); 114 for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; 115 return buf; 116 } 117 118 export function export_table_to_excel(id) { 119 var theTable = document.getElementById(id); 120 console.log('a') 121 var oo = generateArray(theTable); 122 var ranges = oo[1]; 123 124 /* original data */ 125 var data = oo[0]; 126 var ws_name = "SheetJS"; 127 console.log(data); 128 129 var wb = new Workbook(), 130 ws = sheet_from_array_of_arrays(data); 131 132 /* add ranges to worksheet */ 133 // ws['!cols'] = ['apple', 'banan'];

//合并单元格 134 ws['!merges'] = ranges; 135 136 /* add worksheet to workbook */ 137 wb.SheetNames.push(ws_name); 138 wb.Sheets[ws_name] = ws; 139 140 var wbout = XLSX.write(wb, { 141 bookType: 'xlsx', 142 bookSST: false, 143 type: 'binary' 144 }); 145 146 saveAs(new Blob([s2ab(wbout)], { 147 type: "application/octet-stream" 148 }), "test.xlsx") 149 } 150 151 function formatJson(jsonData) { 152 console.log(jsonData) 153 } 154 export function export_json_to_excel(multiHeader, th, merges, data, defaultTitle) { 155 data = [...data]; 156 data.unshift(th); 157 158 159 if (multiHeader) { 160 data.unshift(multiHeader); 161 } 162 var ws_name = "SheetJS"; 163 164 var wb = new Workbook(), 165 ws = sheet_from_array_of_arrays(data); 166 167 /* add worksheet to workbook */ 168 wb.SheetNames.push(ws_name);
//合并单元格
169 ws["!merges"] = merges; 170 wb.Sheets[ws_name] = ws; 171 172 var dataInfo = wb.Sheets[wb.SheetNames[0]]; 173 var cellArr = merges.map(c => c.s); 174 var secArr = merges.map(c => c.e); 175 var cellArr1 = []; 176 cellArr.forEach(cellObj => { 177 var cell_ref = XLSX.utils.encode_cell({ 178 c: cellObj.c, 179 r: cellObj.r 180 }); 181 cellArr1.push(cell_ref); 182 }); 183
//设置单元格样式 184 const borderAll = { 185 border: { 186 //单元格外侧框线 187 top: { 188 style: "thin" 189 }, 190 bottom: { 191 style: "thin" 192 }, 193 left: { 194 style: "thin" 195 }, 196 right: { 197 style: "thin" 198 } 199 } 200 }; 201 //给所有单元格加上边框 202 for (var i in dataInfo) { 203 if (i == '!ref' || i == '!merges' || i == '!cols' || $.inArray(i, cellArr1) >= 0) { 204 205 } else { 206 dataInfo[i + ''].s = borderAll; 207 } 208 } 209 //设置单元格背景色、字体以及字体大小等 210 var bgColArr = ["FDE9D9", 'FFFF00', 'DAEEF3', 'CCC0DA', 'C5D9F1']; 211 //设置主标题样式 212 var headerStyle = { 213 font: { 214 name: '宋体', 215 color: { 216 rgb: "303133" 217 }, 218 bold: true, 219 italic: false, 220 underline: false 221 }, 222 alignment: { 223 horizontal: "center", 224 vertical: "center" 225 }, 226 fill: { 227 228 } 229 }; 230 let mm = 0; 231 cellArr1.forEach(cellObj => { 232 var hStyle = Object.assign({}, headerStyle); 233 hStyle.fill = { 234 fgColor: { 235 rgb: bgColArr[mm] 236 } 237 }; 238 dataInfo[cellObj].s = hStyle; 239 mm++; 240 }); 241 242 var secCellStyle = Object.assign({}, borderAll, headerStyle); 243 secArr.forEach((s, index) => { 244 var hStyle = Object.assign({}, secCellStyle); 245 hStyle.fill = { 246 fgColor: { 247 rgb: bgColArr[index] 248 } 249 }; 250 var startIndex = 0; 251 if (index == 0) { 252 startIndex = 0; 253 } else { 254 startIndex = secArr[index - 1].c + 1; 255 } 256 for (var se = startIndex; se <= s.c; se++) { 257 var cell_ref = XLSX.utils.encode_cell({ 258 c: se, 259 r: 1 260 }); 261 dataInfo[cell_ref].s = hStyle; 262 } 263 }); 264 265 var wbout = XLSX.write(wb, { 266 bookType: 'xlsx', 267 bookSST: false, 268 type: 'binary' 269 }); 270 var title = defaultTitle || '列表' 271 saveAs(new Blob([s2ab(wbout)], { 272 type: "application/octet-stream" 273 }), title + ".xlsx") 274 }

import XLSX from "xlsx-style" 可能会报cpexcel.js的错误,需要修改源码:

将node_modules/xlsx-style/dist/cpexcel.js 中的var cpt = require('./cpt' + 'able'); 修改为var cpt = cptable;

如果还报fs相关的错误,需要单独配置webpack.base.conf.js,以下是5-7行代码

1 module.exports = {
2     entry: {
3         app: ["babel-polyfill", './src/main.js']
4     },
5     node: {
6         fs: "empty"
7     }
8 }

 

以下是Blod.js源码,不需要做任何处理直接使用即可:

  1 /* eslint-disable */
  2 /* Blob.js
  3  * A Blob implementation.
  4  * 2014-05-27
  5  *
  6  * By Eli Grey, http://eligrey.com
  7  * By Devin Samarin, https://github.com/eboyjr
  8  * License: X11/MIT
  9  *   See LICENSE.md
 10  */
 11 
 12 /*global self, unescape */
 13 /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
 14  plusplus: true */
 15 
 16 /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
 17 
 18 (function (view) {
 19     "use strict";
 20 
 21     view.URL = view.URL || view.webkitURL;
 22 
 23     if (view.Blob && view.URL) {
 24         try {
 25             new Blob;
 26             return;
 27         } catch (e) {}
 28     }
 29 
 30     // Internally we use a BlobBuilder implementation to base Blob off of
 31     // in order to support older browsers that only have BlobBuilder
 32     var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
 33             var
 34                 get_class = function(object) {
 35                     return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
 36                 }
 37                 , FakeBlobBuilder = function BlobBuilder() {
 38                     this.data = [];
 39                 }
 40                 , FakeBlob = function Blob(data, type, encoding) {
 41                     this.data = data;
 42                     this.size = data.length;
 43                     this.type = type;
 44                     this.encoding = encoding;
 45                 }
 46                 , FBB_proto = FakeBlobBuilder.prototype
 47                 , FB_proto = FakeBlob.prototype
 48                 , FileReaderSync = view.FileReaderSync
 49                 , FileException = function(type) {
 50                     this.code = this[this.name = type];
 51                 }
 52                 , file_ex_codes = (
 53                     "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
 54                     + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
 55                 ).split(" ")
 56                 , file_ex_code = file_ex_codes.length
 57                 , real_URL = view.URL || view.webkitURL || view
 58                 , real_create_object_URL = real_URL.createObjectURL
 59                 , real_revoke_object_URL = real_URL.revokeObjectURL
 60                 , URL = real_URL
 61                 , btoa = view.btoa
 62                 , atob = view.atob
 63 
 64                 , ArrayBuffer = view.ArrayBuffer
 65                 , Uint8Array = view.Uint8Array
 66                 ;
 67             FakeBlob.fake = FB_proto.fake = true;
 68             while (file_ex_code--) {
 69                 FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
 70             }
 71             if (!real_URL.createObjectURL) {
 72                 URL = view.URL = {};
 73             }
 74             URL.createObjectURL = function(blob) {
 75                 var
 76                     type = blob.type
 77                     , data_URI_header
 78                     ;
 79                 if (type === null) {
 80                     type = "application/octet-stream";
 81                 }
 82                 if (blob instanceof FakeBlob) {
 83                     data_URI_header = "data:" + type;
 84                     if (blob.encoding === "base64") {
 85                         return data_URI_header + ";base64," + blob.data;
 86                     } else if (blob.encoding === "URI") {
 87                         return data_URI_header + "," + decodeURIComponent(blob.data);
 88                     } if (btoa) {
 89                         return data_URI_header + ";base64," + btoa(blob.data);
 90                     } else {
 91                         return data_URI_header + "," + encodeURIComponent(blob.data);
 92                     }
 93                 } else if (real_create_object_URL) {
 94                     return real_create_object_URL.call(real_URL, blob);
 95                 }
 96             };
 97             URL.revokeObjectURL = function(object_URL) {
 98                 if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
 99                     real_revoke_object_URL.call(real_URL, object_URL);
100                 }
101             };
102             FBB_proto.append = function(data/*, endings*/) {
103                 var bb = this.data;
104                 // decode data to a binary string
105                 if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
106                     var
107                         str = ""
108                         , buf = new Uint8Array(data)
109                         , i = 0
110                         , buf_len = buf.length
111                         ;
112                     for (; i < buf_len; i++) {
113                         str += String.fromCharCode(buf[i]);
114                     }
115                     bb.push(str);
116                 } else if (get_class(data) === "Blob" || get_class(data) === "File") {
117                     if (FileReaderSync) {
118                         var fr = new FileReaderSync;
119                         bb.push(fr.readAsBinaryString(data));
120                     } else {
121                         // async FileReader won't work as BlobBuilder is sync
122                         throw new FileException("NOT_READABLE_ERR");
123                     }
124                 } else if (data instanceof FakeBlob) {
125                     if (data.encoding === "base64" && atob) {
126                         bb.push(atob(data.data));
127                     } else if (data.encoding === "URI") {
128                         bb.push(decodeURIComponent(data.data));
129                     } else if (data.encoding === "raw") {
130                         bb.push(data.data);
131                     }
132                 } else {
133                     if (typeof data !== "string") {
134                         data += ""; // convert unsupported types to strings
135                     }
136                     // decode UTF-16 to binary string
137                     bb.push(unescape(encodeURIComponent(data)));
138                 }
139             };
140             FBB_proto.getBlob = function(type) {
141                 if (!arguments.length) {
142                     type = null;
143                 }
144                 return new FakeBlob(this.data.join(""), type, "raw");
145             };
146             FBB_proto.toString = function() {
147                 return "[object BlobBuilder]";
148             };
149             FB_proto.slice = function(start, end, type) {
150                 var args = arguments.length;
151                 if (args < 3) {
152                     type = null;
153                 }
154                 return new FakeBlob(
155                     this.data.slice(start, args > 1 ? end : this.data.length)
156                     , type
157                     , this.encoding
158                 );
159             };
160             FB_proto.toString = function() {
161                 return "[object Blob]";
162             };
163             FB_proto.close = function() {
164                 this.size = this.data.length = 0;
165             };
166             return FakeBlobBuilder;
167         }(view));
168 
169     view.Blob = function Blob(blobParts, options) {
170         var type = options ? (options.type || "") : "";
171         var builder = new BlobBuilder();
172         if (blobParts) {
173             for (var i = 0, len = blobParts.length; i < len; i++) {
174                 builder.append(blobParts[i]);
175             }
176         }
177         return builder.getBlob(type);
178     };
179 }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));

以下是我的代码层级结构:

 

 

 下面是具体页面的具体调用,直接上代码:

 1     let val = ['MachineNo', 'MachineIndex', 'ProdMonth', 'MachineType', 'StatusStr'];
 2                 let proArr = ['StartTime', 'EndTime', 'ValidTime'];
 3                 let outArr = ['CaseNo', 'ToCountry', 'ToPlace', 'OutTime', 'InvertoryNum', 'OrderTime'];
 4                 let tsArr = ['InstallPlace', 'InstallTime', 'CompCount', 'FinCompTime'];
 5                 val = val.concat(opColKey).concat(acColKey).concat(proArr).concat(partNameArr).concat(outArr).concat(tsArr);
 6                 let startCell = 5 + opColName.length + acColName.length;
//以下是合并单元格
7 let merges = [{ 8 //合并基本情报 9 s: { //s为开始 10 c: 0, //开始列 11 r: 0 //开始取值范围 12 }, 13 e: { //e结束 14 c: (startCell - 1), //结束列 15 r: 0 //结束范围 16 } 17 }, 18 { 19 //合并生产情报 20 s: { //s为开始 21 c: startCell, //开始列 22 r: 0 //开始取值范围 23 }, 24 e: { //e结束 25 c: (startCell + 3 - 1), //结束列 26 r: 0 //结束范围 27 } 28 }, 29 { 30 //合并部件情报 31 s: { //s为开始 32 c: (startCell + 3), //开始列 33 r: 0 //开始取值范围 34 }, 35 e: { //e结束 36 c: (startCell + 3 + this.partNameHeader.length - 1), //结束列 37 r: 0 //结束范围 38 } 39 }, 40 { 41 //合并出库情报 42 s: { //s为开始 43 c: (startCell + 3 + this.partNameHeader.length), //开始列 44 r: 0 //开始取值范围 45 }, 46 e: { //e结束 47 c: (startCell + 3 + this.partNameHeader.length + 6 - 1), //结束列 48 r: 0 //结束范围 49 } 50 }, 51 { 52 //合并技服情报 53 s: { //s为开始 54 c: (startCell + 3 + this.partNameHeader.length + 6), //开始列 55 r: 0 //开始取值范围 56 }, 57 e: { //e结束 58 c: (startCell + 3 + this.partNameHeader.length + 6 + 4 - 1), //结束列 59 r: 0 //结束范围 60 } 61 }, 62 ]; 63 this.exportExcel(multiHeader, tHeader, merges, val, data);
 1 exportExcel(multiHeader, tHeader, merges, val, tableData) {
 2                 require.ensure([], () => {
 3                     const {
 4                         export_json_to_excel
 5                     } = require('../excel/Export2Excel.js');
 6                     let filterVal = val;
 7                     //把后台传过来的数据存到list
 8                     const list = tableData;
 9                     const data = this.formatJson(filterVal, list);
10                     export_json_to_excel(multiHeader, tHeader, merges, data, '统合情报管理报表');
11                 })
12             },
13             formatJson(filterVal, jsonData) {
14                 return jsonData.map(v => filterVal.map(j => v[j]));
15             }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM