background
In project development, we often encounter situations where we need to export data to Excel files. However, this process can be relatively complex and cumbersome, especially for the case of large amounts of data and complex tabular structures. Therefore, we need a general method that can be flexibly used in various scenarios and realize simple and efficient data export operations
Installation dependencies:
npm install file-saver --save npm install script-loader --save-dev npm install xlsx --save
If the project is not using npm, use yarn or pnpm.
Create directory vendor under src
Create two files in the directory
/* eslint-disable */ (function (view) { "use strict"; = || ; if ( && ) { try { new Blob; return; } catch (e) { } } // Internally we use a BlobBuilder implementation to base Blob off of // in order to support older browsers that only have BlobBuilder var BlobBuilder = || || || (function (view) { var get_class = function (object) { return (object).match(/^[object\s(.*)]$/)[1]; } , FakeBlobBuilder = function BlobBuilder() { = []; } , FakeBlob = function Blob(data, type, encoding) { = data; = ; = type; = encoding; } , FBB_proto = , FB_proto = , FileReaderSync = , FileException = function (type) { = this[ = type]; } , file_ex_codes = ( "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" ).split(" ") , file_ex_code = file_ex_codes.length , real_URL = || || view , real_create_object_URL = real_URL.createObjectURL , real_revoke_object_URL = real_URL.revokeObjectURL , URL = real_URL , btoa = , atob = , ArrayBuffer = , Uint8Array = view.Uint8Array ; = FB_proto.fake = true; while (file_ex_code--) { [file_ex_codes[file_ex_code]] = file_ex_code + 1; } if (!real_URL.createObjectURL) { URL = = {}; } = function (blob) { var type = , data_URI_header ; if (type === null) { type = "application/octet-stream"; } if (blob instanceof FakeBlob) { data_URI_header = "data:" + type; if ( === "base64") { return data_URI_header + ";base64," + ; } else if ( === "URI") { return data_URI_header + "," + decodeURIComponent(); } if (btoa) { return data_URI_header + ";base64," + btoa(); } else { return data_URI_header + "," + encodeURIComponent(); } } else if (real_create_object_URL) { return real_create_object_URL.call(real_URL, blob); } }; = function (object_URL) { if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { real_revoke_object_URL.call(real_URL, object_URL); } }; FBB_proto.append = function (data/*, endings*/) { var bb = ; // decode data to a binary string if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { var str = "" , buf = new Uint8Array(data) , i = 0 , buf_len = ; for (; i < buf_len; i++) { str += (buf[i]); } (str); } else if (get_class(data) === "Blob" || get_class(data) === "File") { if (FileReaderSync) { var fr = new FileReaderSync; ((data)); } else { // async FileReader won't work as BlobBuilder is sync throw new FileException("NOT_READABLE_ERR"); } } else if (data instanceof FakeBlob) { if ( === "base64" && atob) { (atob()); } else if ( === "URI") { (decodeURIComponent()); } else if ( === "raw") { (); } } else { if (typeof data !== "string") { data += ""; // convert unsupported types to strings } // decode UTF-16 to binary string (unescape(encodeURIComponent(data))); } }; FBB_proto.getBlob = function (type) { if (!) { type = null; } return new FakeBlob((""), type, "raw"); }; FBB_proto.toString = function () { return "[object BlobBuilder]"; }; FB_proto.slice = function (start, end, type) { var args = ; if (args < 3) { type = null; } return new FakeBlob( (start, args > 1 ? end : ) , type , ); }; FB_proto.toString = function () { return "[object Blob]"; }; FB_proto.close = function () { = = 0; }; return FakeBlobBuilder; }(view)); = function Blob(blobParts, options) { var type = options ? ( || "") : ""; var builder = new BlobBuilder(); if (blobParts) { for (var i = 0, len = ; i < len; i++) { (blobParts[i]); } } return (type); }; }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || || this));
/* eslint-disable */ import {saveAs} from 'file-saver' import * as XLSX from 'xlsx' import XLSXS from "xlsx-style" require('script-loader!file-saver'); require('./Blob');//This is your addressrequire('script-loader!xlsx/dist/'); /** * * @param {*} table * @returns * Convert HTML tables to 2D arrays * Functions support processing of cell merging, row and column spans, and conversion of specific data types in tables */ function generateArray(table) { let out = []; let rows = ('tr'); let ranges = []; for (let R = 0; R < ; ++R) { let outRow = []; let row = rows[R]; let columns = ('td'); for (let C = 0; C < ; ++C) { let cell = columns[C]; let colspan = ('colspan'); let rowspan = ('rowspan'); let cellValue = ; if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue; //Skip ranges (function (range) { if (R >= && R <= && >= && <= .c) { for (let i = 0; i <= - ; ++i) (null); } }); //Handle Row Span if (rowspan || colspan) { rowspan = rowspan || 1; colspan = colspan || 1; ({ s: { r: R, c: }, e: { r: R + rowspan - 1, c: + colspan - 1 } }); } ; //Handle Value (cellValue !== "" ? cellValue : null); //Handle Colspan if (colspan) for (let k = 0; k < colspan - 1; ++k) (null); } (outRow); } return [out, ranges]; }; function datenum(v, date1904) { if (date1904) v += 1462; let epoch = (v); return (epoch - new Date((1899, 11, 30))) / (24 * 60 * 60 * 1000); } /** * * @param {*} data * @param {*} opts * @returns * JavaScript function for converting 2D arrays into Excel worksheet objects * Use the library-provided tooling methods to encode cell references and worksheet scopes to generate worksheet data that can be processed by Excel. * Supports converting some data types to data types supported by Excel, such as converting date objects to numeric types and setting corresponding formats. */ function sheet_from_array_of_arrays(data, opts) { let ws = {}; let range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } }; for (let R = 0; R != ; ++R) { for (let C = 0; C != data[R].length; ++C) { if ( > R) = R; if ( > C) = C; if ( < R) = R; if ( < C) = C; let cell = { v: data[R][C] }; if ( == null) continue; let cell_ref = .encode_cell({ c: C, r: R }); if (typeof === 'number') = 'n'; else if (typeof === 'boolean') = 'b'; else if ( instanceof Date) { = 'n'; = ._table[14]; = datenum(); } else = 's'; ws[cell_ref] = cell; } } if ( < 10000000) ws['!ref'] = .encode_range(range); return ws; } function Workbook() { if (!(this instanceof Workbook)) return new Workbook(); = []; = {}; } function s2ab(s) { let buf = new ArrayBuffer(); let view = new Uint8Array(buf); for (let i = 0; i != ; ++i) view[i] = (i) & 0xFF; return buf; } export function export_table_to_excel(id) { let theTable = (id); let oo = generateArray(theTable); let ranges = oo[1]; /* original data */ let data = oo[0]; let ws_name = "SheetJS"; let 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 */ (ws_name); [ws_name] = ws; let wbout = (wb, { bookType: 'xlsx', bookSST: false, type: 'binary' }); saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), "") } export function export_json_to_excelhb({ multiHeader = [], // The first row of table header multiHeader2 = [], // The second row of table header header = [], // The third row header data,//The data passed filename, //file name merges = [], // Merge autoWidth = true,// Used to set the column width bookType = 'xlsx' } = {}) { /* original data */ filename = filename || 'List'; data = [...data] for (let i = - 1; i > -1; i--) { (header[i]) } for (let i = - 1; i > -1; i--) { (multiHeader2[i]) } for (let i = - 1; i > -1; i--) { (multiHeader[i]) } let ws_name = "SheetJS"; let wb = new Workbook(), ws = sheet_from_array_of_arrays(data); // Set the cell public style let borderAll = { //Outside box line of cell top: { style: 'thin', }, bottom: { style: 'thin', }, left: { style: 'thin', }, right: { style: 'thin', } }; for (let key in ws) { // Cell common style settings if (ws[key] instanceof Object) { ws[key].s = { border: borderAll, alignment: { horizontal: 'center', //Align horizontally centered vertical: 'center',//Center vertically wrapText: 1,// Automatic line wrap }, // fill: { // Background color // fgColor: { rgb: 'dbf3f2' } // }, font: { sz: 10,//Style style and color settings of fonts in cells color: { rgb: '000000' } }, bold: true, numFmt: 0 } } //Add a style to a specific grid (with '1', that is, the first line title), the same is true for the following // if ((/[^0-9]/ig, '') === '1') { // ws[key].s = { // ...ws[key].s, // fill: { // Background color // fgColor: { rgb: 'd4e6fd' } // }, // font: {//Overwrite font // name: 'isoline', // sz: 10, // // bold: true // }, // } // } if (key === 'A1') { ws[key].s = { ...ws[key].s, fill: { //Background color fgColor: {rgb: 'd4e6fd'} }, } } // if (key === 'B2' || key === 'C2' || key === 'D2' || key === 'E2' || key === 'F2' || key === 'G2') { // ws[key].s = { // ...ws[key].s, // fill: { // Background color // fgColor: { rgb: 'fbedd7' } // } // } // } } if ( > 0) { if (!ws['!merges']) ws['!merges'] = []; (item => { ws['!merges'].push(.decode_range( .encode_cell() + ':' + .encode_cell() )); // Set the cell style ws[.encode_cell()].s = ; }); } // ws['I2'] = ws['H2'] = ws['G2'] = ws['F2'] = ws['E2'] = ws['D2'] = ws['C2'] = ws['B2'] = ws['A2']//Style settings for cells in the second row (if it is the first row of merge, it is 1) // if ( > 0) { // if (!ws['!merges']) ws['!merges'] = []; // (item => { // (item); // ws['!merges'].push(.decode_range(item)) // }) // } if (autoWidth) { let colWidths = []; // Calculate all cell widths of each column // traverse the line first ((row) => { // Column number let index = 0 // traverse columns for (const key in row) { if (colWidths[index] == null) colWidths[index] = [] switch (typeof row[key]) { case 'string': case 'number': case 'boolean': colWidths[index].push(getCellWidth(row[key])) break case 'object': case 'function': colWidths[index].push(0) break } index++ } }) ws['!cols'] = []; // Settings of the third row header ((widths, index) => { // Calculate the width of the column header // (getCellWidth(header[index])) // Set the maximum value to column width ws['!cols'].push({ wch: (...widths) }) }) } /* add worksheet to workbook */ (ws_name); [ws_name] = ws; let wbout = (wb, { bookType: bookType, bookSST: false, type: 'binary' }); saveAs(new Blob([s2ab(wbout)], { type: "application/octet-stream" }), `${filename}.${bookType}`); } export function getCellWidth(value) { if (value == null) { return 10 } else if (().charCodeAt(0) > 255) { // Determine whether it contains Chinese let length = ().length * 2 if (length > 60) { length = length - 40 //The width here can be set by yourself. Set wrapText in the front: 1 You can wrap lines in the cell } return length } else { return ().length * 1.2 } }
import {saveAs} from 'file-saver' import * as XLSX from 'xlsx' import XLSXS from "xlsx-style" `file-saver`Importing in the library`saveAs`function,Used to save files。 `xlsx`Importing in the library所有的功能,And take it as`XLSX`Object reference。 `xlsx-style`Library import supports styles,And name it`XLSXS`。
require('script-loader!file-saver'); require('./Blob');//This is your addressrequire('script-loader!xlsx/dist/'); This part of the code uses`require`and`script-loader`Come to loadand引入所需的脚本document。 in,pass`script-loader!file-saver`Come to load`file-saver`Scripts required by the library, `require('./Blob')`Used to load custom``document, `script-loader!xlsx/dist/`For loading`xlsx`The core script of the library。
The specific paths and file names in the above code snippets may vary depending on your project structure, and you need to adjust them according to the actual situation.
Through the above steps, you can use it in your projectsaveAs()
Functions save files locally and useXLSX
andXLSXS
Objects perform processing and operation of Excel files.
Code implementation
There are many files on the Internet, which are subtle and basically the same according to the individual project, but there are a lot of data charts and various types of tables in the project. Without a general method of encapsulation, the number of code duplication will increase and will not be easy to maintain.
Therefore, I made a general method based on Export2Excel, the code is as follows:
Create a vendor/ file
// Export Excel general methodasync function exportExcel(multiHeader, multiHeader2, filterVal, tableData, tabulationTitle, indexNumber) { // Export title const EXPORT_FILENAME = tabulationTitle; // Cell style 1 dbf3f2 const style1 = { fill: {patternType: 'solid', fgColor: {rgb: 'dbf3f2'}}, border: {top: {style: 'thin'}, left: {style: 'thin'}, bottom: {style: 'thin'}, right: {style: 'thin'}}, alignment: {horizontal: 'center', vertical: 'center', wrapText: 1} }; // Cell style 2 fbedd7 const style2 = { fill: {patternType: 'solid', fgColor: {rgb: 'fbedd7'}}, border: {top: {style: 'thin'}, left: {style: 'thin'}, bottom: {style: 'thin'}, right: {style: 'thin'}}, alignment: {horizontal: 'center', vertical: 'center', wrapText: 1} }; // Combine cells of all headers let headerList = []; let titleList = []; let styleNumber = 1; // Initially 1 level header style judgment let headerStyle = style2; let rowIndex = 1; let colIndex = 1; let isOdd = true; let count = 0; const indexNumber2 = indexNumber + 1 // First-level header merge and color assignment if (multiHeader[0] && multiHeader[0].length > 0) { multiHeader[0].forEach((group, index) => { if (rowIndex < multiHeader[0].length) { ({s: {r: 0, c: rowIndex}, e: {r: 0, c: rowIndex + indexNumber}, style: headerStyle}); rowIndex += indexNumber2; } // Modify the style value if (styleNumber === 1) { styleNumber = 2 // Modify the style value headerStyle = style1 } else { styleNumber = 1 // Modify the style value headerStyle = style2 } }); } if (multiHeader2[0] && multiHeader2[0].length > 0) { multiHeader2[0].forEach((group, index) => { if (colIndex < multiHeader2[0].length) { ({s: {r: 1, c: colIndex}, e: {r: 1, c: colIndex}, style: isOdd ? style2 : style1}); colIndex += 1; count++; } if (count % indexNumber2 === 0) { isOdd = !isOdd; } }); } // Combine cells of all headers const merges = [ // Merge A1 and A2 and set background color 1 { s: {r: 0, c: 0}, e: {r: 1, c: 0}, style: { fill: {patternType: 'solid', fgColor: {rgb: 'd4e6fd'}}, border: {top: {style: 'thin'}, left: {style: 'thin'}, bottom: {style: 'thin'}, right: {style: 'thin'}}, alignment: {horizontal: 'center', vertical: 'center', wrapText: 1} } }, ...headerList, ...titleList // Secondary table header ]; const data = ((v) => ((j) => v[j])); await import('/src/vendor/').then((excel) => { excel.export_json_to_excelhb({ multiHeader, // Here is the header of the first row multiHeader2, // Here is the header of the second row data, filename: EXPORT_FILENAME, merges }); }); } export default {exportExcel}
The code given above is an example of exporting a common method for Excel. Let's gradually analyze the key logic:
- First, in the function parameters, we pass in some necessary parameters, such as multi-level header (
multiHeader
andmultiHeader2
), data filtering column (filterVal
), table data (tableData
), table title (tabulationTitle
) and index number (indexNumber
). These parameters are used as input to the function to generate an Excel file. - Next, we define some constants, such as export file name (
EXPORT_FILENAME
) and two cell styles of different styles (style1
andstyle2
). These styles can be used to beautify the exported Excel tables, making them more readable and professional. - After the header merge and style setting, we use
import
The syntax is introduced withlibrary file. This library file is a core tool used to implement data export to Excel, we can call it
export_json_to_excelhb
Method to implement the export function. - Finally, we call the sorted data, file name to be exported, header style and cell merging information as parameters.
export_json_to_excelhb
Method implements the export operation.
Export Example
Introduce the global
import Excel from './vendor/exportExcel' .$Excel = Excel;
// Call the export Excel common methodasync exportExcelDemo() { let multiHeader = []; // The header of the first row let multiHeader2 = [] // The header of the second row let filterVal = [] // Corresponding fields multiHeader = [[, 'Game Hall', '', '', 'Game Hall', '', '', 'Internet cafe', '', '',]] multiHeader2 = [['', , , 'Year-on-year', , , 'Year-on-year', , , 'Year-on-year',]]; filterVal = ['areaName', 'sumValue03', 'momPerCent', 'yoyPerCent', 'sumValue032', 'momPerCent2', 'yoyPerCent2', 'sumValue033', 'momPerCent3', 'yoyPerCent3', ]; const tabulationTitle = 'Export Table'; // Export title const indexNumber = === 'day' ? 6 : 7 //Adjust according to business needs, the required field data is also different await this.$(multiHeader, multiHeader2, filterVal, tableData, tabulationTitle,indexNumber); } // Call example();
Application scenarios
This general export Excel method is suitable for a variety of front-end development scenarios, such as:
- In a data visualization project, export the chart data to an Excel file for further analysis and processing.
- In the data management system, the query data is exported into Excel tables, which is convenient for users to use and share offline.
- In the e-commerce platform, product information, sales reports, etc. are exported into Excel files to facilitate merchants to conduct business analysis and statistics.
Summarize
Through this general export Excel method, we can easily handle various data export requirements and can adapt to different table structures and data volumes. Just simply configure parameters to generate beautiful, easy to read and process Excel files.
I hope this article can be helpful to everyone's data export needs in front-end development.
The above is a detailed explanation of the general methods of JS front-end to easily export Excel. For more information on JS general methods of exporting Excel, please pay attention to my other related articles!