I have a similar question to this question(Javascript: Exporting large text/csv file crashes Google Chrome):
I am trying to save the data created by excelbuilder.js‘s EB.createFile()
function. If I put the file data as the href
attribute value of a link, it works. However, when data is big, it crashes Chrome browser. Code are like this:
//generate a temp <a /> tag
var link = document.createElement("a");
link.href = 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,' + encodeURIComponent(data);
link.style = "visibility:hidden";
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
My code to create the data using excelbuilder.js is like follows:
var artistWorkbook = EB.createWorkbook();
var albumList = artistWorkbook.createWorksheet({name: 'Album List'});
albumList.setData(originalData);
artistWorkbook.addWorksheet(albumList);
var data = EB.createFile(artistWorkbook);
As suggested by the answer of the similar question (Javascript: Exporting large text/csv file crashes Google Chrome), a blob needs to be created.
My problem is, what is saved in the file isn’t a valid Excel file that can be opened by Excel. The code that I use to save the blob
is like this:
var blob = new Blob(
[data],
{type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,"}
);
// Programatically create a link and click it:
var a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = fileName;
a.click();
If I replace the [data]
in the above code with [Base64.decode(data)]
, the contents in the file saved looks more like the expected excel data, but still cannot be opened by Excel.
The answer above is correct. Please be sure that you have a string data in base64 in the data variable without any prefix or stuff like that just raw data.
Here’s what I did on the server side (asp.net mvc core):
string path = Path.Combine(folder, fileName);
Byte[] bytes = System.IO.File.ReadAllBytes(path);
string base64 = Convert.ToBase64String(bytes);
On the client side, I did the following code:
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.setRequestHeader("Content-Type", "text/plain");
xhr.onload = () => {
var bin = atob(xhr.response);
var ab = s2ab(bin); // from example above
var blob = new Blob([ab], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;' });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'demo.xlsx';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
xhr.send();
And it works perfectly for me.
I’ve found a solution worked for me:
const handleDownload = async () => {
const req = await axios({
method: "get",
url: `/companies/${company.id}/data`,
responseType: "blob",
});
var blob = new Blob([req.data], {
type: req.headers["content-type"],
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = `report_${new Date().getTime()}.xlsx`;
link.click();
};
I just point a responseType: «blob»
I had the same problem as you. It turns out you need to convert the Excel data file to an ArrayBuffer.
var blob = new Blob([s2ab(atob(data))], {
type: ''
});
href = URL.createObjectURL(blob);
The s2ab (string to array buffer) method (which I got from https://github.com/SheetJS/js-xlsx/blob/master/README.md) is:
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;
}
This works as of: v0.14.0 of https://github.com/SheetJS/js-xlsx
/* generate array buffer */
var wbout = XLSX.write(wb, {type:"array", bookType:'xlsx'});
/* create data URL */
var url = URL.createObjectURL(new Blob([wbout], {type: 'application/octet-stream'}));
/* trigger download with chrome API */
chrome.downloads.download({ url: url, filename: "testsheet.xlsx", saveAs: true });
Preface
Recently, the company needs to export several statistical tables to excel. Because the company’s existing export excel function is front-end and back-end export, it is troublesome, so I want to find a pure front-end export tool, and finally found js-xlsx, which is highly rated, but the Chinese documents were not found, Baidu did not find a more comprehensive one.Tutorial, so I stepped on a lot of pits, I record them for future use.
Environmental Science
Since my business only uses exporting the contents of a table tag to excel, I only write how to export the contents of a table element to excel.It can also be exported through json, which seems simpler.
install
GitHub address
npm installation
npm install xlsx
After installation, there is a file named xlsx.full.min.js under the dist folder, which was introduced into the project
First example
Code first
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <table id="table1" border="1" cellspacing="0" cellpadding="0" > <thead> <tr> <td>Sequence Number</td> <td>Full name</td> <td>Age</td> <td>Interest</td> </tr> </thead> <tbody> <tr> <td>1</td> <td>Zhang San</td> <td>18</td> <td>Play games</td> </tr> <tr> <td>2</td> <td>Li Si</td> <td>88</td> <td>Watch movie</td> </tr> <tr> <td>3</td> <td>King Five</td> <td>81</td> <td>Sleep</td> </tr> </tbody> </table> <button id="btn" onclick="btn_export()">export</button> </body> <script src="js/xlsx.full.min.js"></script> <script src="js/export.js"></script> <script> function btn_export() { var table1 = document.querySelector("#table1"); var sheet = XLSX.utils.table_to_sheet(table1);//Convert a table object to a sheet object openDownloadDialog(sheet2blob(sheet),'download.xlsx'); } </script> </html>
Running effect
Export results:
As you may notice, I’ve introduced an export.js file here. There are only two methods in this export.js file: openDownload Dialog (sheet2blob,’download.xlsx’), which is used in the code above.
This is the code for export.js:
// Turn a sheet into a blob object for the final excel file and download it using the URL.createObjectURL function sheet2blob(sheet, sheetName) { sheetName = sheetName || 'sheet1'; var workbook = { SheetNames: [sheetName], Sheets: {} }; workbook.Sheets[sheetName] = sheet; // Generate excel configuration items var wopts = { bookType: 'xlsx', // File type to generate bookSST: false, // Whether to generate Shared String Table or not, the official explanation is that the build speed will decrease if turned on, but there is better compatibility on lower version IOS devices type: 'binary' }; var wbout = XLSX.write(workbook, wopts); var blob = new Blob([s2ab(wbout)], { type: "application/octet-stream" }); // String to ArrayBuffer 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; } return blob; } function openDownloadDialog(url, saveName) { if (typeof url == 'object' && url instanceof Blob) { url = URL.createObjectURL(url); // Create a blob address } var aLink = document.createElement('a'); aLink.href = url; aLink.download = saveName || ''; // HTML5 new property, specify save file name, may not suffix, note that file:///mode will not take effect var event; if (window.MouseEvent) event = new MouseEvent('click'); else { event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); } aLink.dispatchEvent(event); }
PS: These two methods are online. Original Address .The author writes very well and finds clues here as well.
If your table tag contains operations to merge cells, XLSX.utils.table_to_sheet(*) can also be read, and the results you print can also be displayed, image:
As you can see, the tables in excel have also been merged.
But in reality, if the customer feels that the line is not centered, he will talk to you about not centering anything, so we’ll solve the problem of not centering the text now.
Set Style (Center, Text Size Color, Background Color…)
PS: This is the place where I walk the most holes…
There’s no looping around here. If you set the style, the xlsx.full.min.js above won’t work.
xlsx-style must be installed
Install xlsx-style
It looks like only npm is installed, github I can’t find an address
npm install xlsx-style
Similarly, there is an xlsx.full.min.js in the dist folder under the installation directory, huh?Same name?How to use it?Okay, I can’t get started, so I’ll just have to put my scalp on it. Note that I put the JS file for xlsx-style below:
There is also the btn_export() method to change, adding a style.
Specific cell style instructions can be found in this article xlsx-style cell style reference table
function btn_export() { var table1 = document.querySelector("#table1"); var sheet = XLSX.utils.table_to_sheet(table1); //This is the code to modify the format sheet["A5"].s = { font: { sz: 13, bold: true, }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; openDownloadDialog(sheet2blob(sheet),'download.xlsx'); }
After changing, click Run, otherwise, the error is reported:
What’s the reason, because the variables exposed by both js files are called’XLSX’, but there is no XLSX.utils method in the xlsx-style js file, and the xlsx-style js file was introduced later, it overwrites the previous XLSX, so the error is reported.
There are many methods available in XLSX.utils, but they cannot be invoked in this way:
You might want to swap two js files, but the result is that xlsx exposed variables override xlsx-style exposed variables.You still can’t change your style.
Be careful
If your export function is to import json format or other formats without using XLSX.utils, you only need to use xlsx-style’s js. The following can be ignored. The following is how to make xlsx work with xlsx-style’s js.
Not using XLSX.utils
Since these two JS are encrypted content, it is impossible to interpret them and find anything useful on them.Fortunately, xlsx.extendscript.js was found in the xlsx dist folder. Look at this file as a tool class. Since I used the table_to_sheet method above, I searched over xlsx.extendscript and found this method. Next, delete the JS reference of xlsx and introduce xlsx.extendscript:
Function.As a result, you should have guessed that the style hasn’t changed.For what reason, the variables exposed by xlsx.extendscript.js are still’XLSX’, and the variables below cover the variables above.
Be careful!!!
If you use webpack, babel, etc. in your project, you can import directly without changing the variable name
Fortunately, this xlsx.extendscript.js is not a compressed version. You can modify the content by changing the exposed variable to’XLSX2′.This way we only use xlsx.extendscript.js when using the utils tool and xlsx-style as the JS for the rest, so that’s fine.
Don’t forget to change XSLX.utils.table_to_sheet() to XLSX2.utils.table_to_sheet() once you’ve modified it.
(It is not recommended to modify the source code, because the work requires that you do not modify the source code before it can be used)
function btn_export() { var table1 = document.querySelector("#table1"); var sheet = XLSX2.utils.table_to_sheet(table1); sheet["A5"].s = { font: { sz: 13, bold: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; openDownloadDialog(sheet2blob(sheet), 'download.xlsx'); }
Function:
You can see that the styling changes you made have taken effect.
Customer demand is increasing: I want the first few lines to be empty and print the company name on them.
Looking at the xlsx.extendscript.js source, it is found that table_to_sheet, or parse_dom_table, does not have a parameter set for the starting row. The code for parse_dom_table is given below:
function parse_dom_table(table, _opts) { var opts = _opts || {}; if(DENSE != null) opts.dense = DENSE; var ws = opts.dense ? ([]) : ({}); var rows = table.getElementsByTagName('tr'); var sheetRows = opts.sheetRows || 10000000; var range = {s:{r:0,c:0},e:{r:0,c:0}}; var merges = [], midx = 0; var rowinfo = []; var _R = 0, R = 0, _C, C, RS, CS; for(; _R < rows.length && R < sheetRows; ++_R) { var row = rows[_R]; if (is_dom_element_hidden(row)) { if (opts.display) continue; rowinfo[R] = {hidden: true}; } var elts = (row.children); for(_C = C = 0; _C < elts.length; ++_C) { var elt = elts[_C]; if (opts.display && is_dom_element_hidden(elt)) continue; var v = htmldecode(elt.innerHTML); for(midx = 0; midx < merges.length; ++midx) { var m = merges[midx]; if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; } } /* TODO: figure out how to extract nonstandard mso- style */ CS = +elt.getAttribute("colspan") || 1; if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); var o = {t:'s', v:v}; var _t = elt.getAttribute("t") || ""; if(v != null) { if(v.length == 0) o.t = _t || 'z'; else if(opts.raw || v.trim().length == 0 || _t == "s"){} else if(v === 'TRUE') o = {t:'b', v:true}; else if(v === 'FALSE') o = {t:'b', v:false}; else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; else if(!isNaN(fuzzydate(v).getDate())) { o = ({t:'d', v:parseDate(v)}); if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}); o.z = opts.dateNF || SSF._table[14]; } } if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; } else ws[encode_cell({c:C, r:R})] = o; if(range.e.c < C) range.e.c = C; C += CS; } ++R; } if(merges.length) ws['!merges'] = merges; if(rowinfo.length) ws['!rows'] = rowinfo; range.e.r = R - 1; ws['!ref'] = encode_range(range); if(R >= sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don't to improve the performance return ws; }
Add one yourself
As you can see, the R variable inside is the key to controlling the starting line. Okay, let’s make some changes:
var _R = 0, R = _opts.rowIndex || 0, _C, C, RS, CS;
Here we add an attribute, rowIndex, to _opts, which is passed in when the table_to_sheet method is called.Here is the changed code:
function btn_export() { var table1 = document.querySelector("#table1"); var opt = { rowIndex: 4 }; //Start empty 4 lines var sheet = XLSX2.utils.table_to_sheet(table1, opt); sheet["A1"] = { t: "s", v: 'Sanlu Group Ltd.' }; //Assign values to A1 cells sheet["A1"].s = { font: { name: 'Song Style', sz: 24, bold: true, underline: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true }, fill: { bgColor: { rgb: 'ffff00' } } }; //['!merges'] This property is designed for cell merging sheet["!merges"].push({//If not null push is null = assign //Merge cell index starts at 0 s: { //s Start c: 0, //Beginning column r: 0 //Start Line }, e: { //e End c: 3, //End Column r: 2 //End line } }); sheet["A9"].s = { //style font: { sz: 13, bold: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; openDownloadDialog(sheet2blob(sheet), 'download.xlsx'); }
Run result:
You can see that the changes you made have taken effect.
Customers have new requirements, to add 2 fields, ID number and mobile phone number.
Isn’t that easy? Add two fields.2 minutes, export:
???
How did the ID number become a scientific method of counting and what the ghost was (later it was found that the percentage would be converted directly to 0-1 decimals for you, but statistics can’t be done)
What’s going on? Or a masterpiece of parse_dom_table!
Note this line:
else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
This means that as long as the value read from the text of td is followed by a number (regardless of your string type), a fuzzynum(v) will be given to you to convert to a numbertype.
Make the following changes, the result is:
function parse_dom_table(table, _opts) { var opts = _opts || {}; if(DENSE != null) opts.dense = DENSE; var ws = opts.dense ? ([]) : ({}); var rows = table.getElementsByTagName('tr'); var sheetRows = opts.sheetRows || 10000000; var range = {s:{r:0,c:0},e:{r:0,c:0}}; var merges = [], midx = 0; var rowinfo = []; var _R = 0, R = _opts.rowIndex || 0, _C, C, RS, CS; for(; _R < rows.length && R < sheetRows; ++_R) { var row = rows[_R]; if (is_dom_element_hidden(row)) { if (opts.display) continue; rowinfo[R] = {hidden: true}; } var elts = (row.children); for(_C = C = 0; _C < elts.length; ++_C) { var elt = elts[_C]; if (opts.display && is_dom_element_hidden(elt)) continue; var v = htmldecode(elt.innerHTML); for(midx = 0; midx < merges.length; ++midx) { var m = merges[midx]; if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; } } /* TODO: figure out how to extract nonstandard mso- style */ CS = +elt.getAttribute("colspan") || 1; if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); var o = {t:'s', v:v}; var _t = elt.getAttribute("t") || ""; if(v != null) { if(v.length == 0) o.t = _t || 'z'; else if(opts.raw || v.trim().length == 0 || _t == "s"){} else if(v === 'TRUE') o = {t:'b', v:true}; else if(v === 'FALSE') o = {t:'b', v:false}; //else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; else if(!isNaN(fuzzynum(v))) o = {t:'s', v:v};//number type is not automatically formatted else if(!isNaN(fuzzydate(v).getDate())) { o = ({t:'d', v:parseDate(v)}); if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}); o.z = opts.dateNF || SSF._table[14]; } } if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; } else ws[encode_cell({c:C, r:R})] = o; if(range.e.c < C) range.e.c = C; C += CS; } ++R; } if(merges.length) ws['!merges'] = merges; if(rowinfo.length) ws['!rows'] = rowinfo; range.e.r = R - 1; ws['!ref'] = encode_range(range); if(R >= sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don't to improve the performance return ws; }
Comment out the converted statement, rewrite the line of code, and if it is of type number, leave it unchanged as to what value it should be or what value it should be.
Now rerun, the result is:
You can see that the numbers are displayed properly.But this cell doesn’t seem to expand automatically, it’s always so big, and xlsx-style also provides a way to control the width of the cell:
sheet["!cols"] = [{ wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 150 }, { wpx: 120 }]; //Cell Column Width
Note that setting cell column widths starts with the first row
Result:
Full front-end code:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <table id="table1" border="1" cellspacing="0" cellpadding="0"> <thead> <tr> <td>Sequence Number</td> <td>Full name</td> <td>Age</td> <td>Interest</td> <td>ID number</td> <td>Cell-phone number</td> </tr> </thead> <tbody> <tr> <td>1</td> <td>Zhang San</td> <td>18</td> <td>Play games</td> <td>320322184087562589</td> <td>1374569821</td> </tr> <tr> <td>2</td> <td>Li Si</td> <td>88</td> <td>Watch movie</td> <td>420322184087562589</td> <td>2374569821</td> </tr> <tr> <td>3</td> <td>King Five</td> <td>81</td> <td>Sleep</td> <td>520322184087562589</td> <td>3374569821</td> </tr> <tr> <td colspan="4">This is a merged cell</td> </tr> </tbody> </table> <button id="btn" onclick="btn_export()">export</button> </body> <script src="js/xlsx.extendscript.js"></script> <script src="js/xlsx-style/xlsx.full.min.js"></script> <script src="js/export.js"></script> <script> function btn_export() { var table1 = document.querySelector("#table1"); var opt = { rowIndex: 4 }; //Start empty 4 lines var sheet = XLSX2.utils.table_to_sheet(table1, opt); sheet["A1"] = { t: "s", v: 'Sanlu Group Ltd.' }; //Assign values to A1 cells sheet["A1"].s = { font: { name: 'Song Style', sz: 24, bold: true, underline: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true }, fill: { bgColor: { rgb: 'ffff00' } } }; //['!merges'] This property is designed for cell merging sheet["!merges"].push({ //If not null push is null = assign //Merge cell index starts at 0 s: { //s Start c: 0, //Beginning column r: 0 //Start Line }, e: { //e End c: 3, //End Column r: 2 //End line } }); sheet["A9"].s = { //style font: { sz: 13, bold: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; sheet["!cols"] = [{ wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 150 }, { wpx: 120 }]; //Cell Column Width openDownloadDialog(sheet2blob(sheet), 'download.xlsx'); } </script> </html>
demo source
github address Full Instance
summary
- Source modification is not recommended in exceptional circumstances
- Since the code was modified after all, this approach can only be targeted to a smaller audience
- I’ve heard that the toll version is full of features. I suggest you buy the toll version if you need it, but the address can’t be found.
- You can modify the xlsx source code to suit your own needs.However, this is more difficult to maintain, so it is up to you to choose between them.
- I have just listed the functions I need in my actual work. xlsx has so many functions that I can think over more when I have time.
js-xlsx введение
кSheetJSПроизведеноjs-xlsx
Это очень удобная библиотека инструментов, которой для чтения и экспорта в Excel нужен только чистый JS. Она имеет мощные функции, поддерживает множество форматов и поддерживаетxls
、xlsx
、ods
(Собственный формат файлов таблицы OpenOffice) и более десятка форматов. Вся эта статья основана наxlsx
Возьмем, к примеру, формат.
- Официальный гитхаб:https://github.com/SheetJS/js-xlsx
- Онлайн-демонстрационный адрес поддерживающей демонстрации для этой статьи:http://demo.haoji.me/2017/02/08-js-xlsx/
- Эта статья впервые была опубликована у меня синхронноличный блогсБлог сад。
1.1. Совместимость
Совместимость следующая:
1.2. Как пользоваться
dist
В каталоге много JS-файлов, обычно используйтеxlsx.core.min.js
довольно,xlsx.full.min.js
Он содержит все функциональные модули.
непосредственныйscript
Этикетка может быть введена:
<script type="text/javascript" src="./js/xlsx.core.min.js"></script>
Читать в Excel
Чтение в Excel происходит в основном черезXLSX.read(data, {type: type});
Способ достижения, ответьте на звонокWorkBook
Основные значения типа следующие:
base64
: Читать в режиме base64;binary
: Формат BinaryString (n-й байт — это data.charCodeAt (n))string
: Строка в кодировке UTF8;buffer
: nodejs Buffer;array
: Uint8Array, 8-битный беззнаковый массив;file
: Путь к файлу (поддерживается только в nodejs);
2.1. Получить объект книги
2.1.1. Чтение локальных файлов
Непосредственно по коду:
// читаем локальный файл Excel
function readWorkbookFromLocalFile(file, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
var workbook = XLSX.read(data, {type: 'binary'});
if(callback) callback(workbook);
};
reader.readAsBinaryString(file);
}
2.1.2. Чтение сетевых файлов
// Чтобы прочитать файл Excel из Интернета, URL-адрес должен находиться в том же домене, иначе будет сообщено об ошибке
function readWorkbookFromRemoteFile(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if(xhr.status == 200) {
var data = new Uint8Array(xhr.response)
var workbook = XLSX.read(data, {type: 'array'});
if(callback) callback(workbook);
}
};
xhr.send();
}
2.2. Подробная рабочая тетрадь
2.2.1. Workbook Object
workbook
Что в нем, распечатаем и посмотрим:
можно увидеть,SheetNames
В нем сохраняются все названия листов, а затемSheets
Конкретное содержимое каждого листа сохраняется (мы называем этоSheet Object
). Каждыйsheet
Через что-то вродеA1
Такое значение ключа сохраняет содержимое каждой ячейки, и мы называем его объектом ячейки (Cell Object
):
2.2.2. Sheet Object
КаждыйSheet Object
Представляет форму, если она не!
Те, что в начале, указывают на обычныеcell
, В противном случае это означает какое-то особое значение, а именно:
sheet['!ref']
: Указывает диапазон всех ячеек, например, от A1 до F8, он записывается какA1:F8
;sheet[!merges]
: Хранить некоторую информацию о слиянии ячеек, это массив, каждый массив состоит изs
сe
Составьте композицию объекта,s
Значит старт,e
Означает конец,r
Представляет строку,c
Представляет столбец;- и многое другое;
Что касается слияния ячеек, в принципе не проблема понять следующую картину:
Результаты приведены ниже:
2.2.3. Объект Cell
Каждая ячейка — это объект (Cell Object
),Естьt
、v
、r
、h
、w
И другие поля (см.Здесь):
- t: указывает тип содержимого,
s
Представляет тип строки,n
Представляет числовой тип,b
Представляет логический тип,d
Представляет тип даты и т. Д. - v: представляет исходное значение;
- f: представляет формулу, например
B2+B3
; - h: HTML-контент
- w: форматированный контент
- r: богатый текстовый контент
rich text
- и многое другое
2.2.4. Читать книгу
Обычный метод:
// читаем файл Excel
function outputWorkbook(workbook) {
var sheetNames = workbook.SheetNames; // набор имен рабочих листов
sheetNames.forEach(name => {
var worksheet = workbook.Sheets [name]; // Указанный рабочий лист можно получить только по имени рабочего листа
for(var key in worksheet) {
// v - исходное значение прочитанной ячейки
console.log(key, key[0] === '!' ? worksheet[key] : worksheet[key].v);
}
});
}
в соответствии с!ref
Определите сферу применения Excel, а затем в соответствии с!merges
Убедитесь, что ячейки объединены (если есть), и, наконец, выведите всю таблицу, что вызывает затруднения. К счастью, сам плагин уже написал инструментXLSX.utils
Для непосредственного использования, без нашего собственного обхода, выходные данные инструмента в основном включают следующее:
Некоторые из них обычно не используются, наиболее часто используются:
XLSX.utils.sheet_to_csv
: Создать формат CSVXLSX.utils.sheet_to_txt
: Создать текстовый форматXLSX.utils.sheet_to_html
: Создать формат HTMLXLSX.utils.sheet_to_json
: Выходной формат JSON
Чаще всего используютсяsheet_to_csv
или жеsheet_to_html
, Формат, объединение ячеек и другая информация будут игнорироваться при преобразовании в CSV, поэтому сложные таблицы могут быть неприменимы. Если вы конвертируете в html, ячейки будут объединены, но результат будет<html></html>
Код вместо<table></table>
, Это неудобно, когда вам нужно внести некоторые изменения в форму, поэтому вам все равно придется использовать соответствующие инструменты в зависимости от ситуации.
Вот простой пример вывода результатов путем преобразования в CSV, вы можете щелкнуть здесь, чтобы просмотретьДЕМО онлайн:
function readWorkbook(workbook)
{
var sheetNames = workbook.SheetNames; // набор имен рабочих листов
var worksheet = workbook.Sheets [sheetNames [0]]; // здесь мы читаем только первый лист
var csv = XLSX.utils.sheet_to_csv(worksheet);
document.getElementById('result').innerHTML = csv2table(csv);
}
// Преобразование csv в простую таблицу, игнорирование слияния ячеек, добавление индекса, аналогичного excel, в первой строке и первом столбце
function csv2table(csv)
{
var html = '<table>';
var rows = csv.split('n');
rows.pop (); // последняя строка бесполезна
rows.forEach(function(row, idx) {
var columns = row.split(',');
columns.unshift (idx + 1); // добавляем индекс строки
if (idx == 0) {// добавляем индекс столбца
html += '<tr>';
for(var i=0; i<columns.length; i++) {
html += '<th>' + (i==0?'':String.fromCharCode(65+i-1)) + '</th>';
}
html += '</tr>';
}
html += '<tr>';
columns.forEach(function(column) {
html += '<td>'+column+'</td>';
});
html += '</tr>';
});
html += '</table>';
return html;
}
Экспорт в Excel
Существует два типа экспорта: один основан на существующей модификации Excel, другой — нового поколения, первый относительно прост, здесь мы сосредоточимся на втором.
3.1. Создайте собственный рукописный код
Экспорт файла Excel, в основном, как его создатьsheet
, Здесь мы пишем простой пример csv для Excel:
// csv в объект листа
function csv2sheet(csv) {
var sheet = {}; // лист, который будет сгенерирован
csv = csv.split('n');
csv.forEach(function(row, i) {
row = row.split(',');
if(i == 0) sheet['!ref'] = 'A1:'+String.fromCharCode(65+row.length-1)+(csv.length-1);
row.forEach(function(col, j) {
sheet[String.fromCharCode(65+j)+(i+1)] = {v: col};
});
});
return sheet;
}
// Преобразование листа в объект blob окончательного файла Excel, а затем использование URL.createObjectURL для загрузки
function sheet2blob(sheet, sheetName) {
sheetName = sheetName || 'sheet1';
var workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = sheet;
// Создание элементов конфигурации для Excel
var wopts = {
bookType: 'xlsx', // тип создаваемого файла
bookSST: false, // Следует ли генерировать общую таблицу строк, официальное объяснение состоит в том, что если она включена, скорость генерации уменьшится, но есть лучшая совместимость с устройствами IOS более низкой версии
type: 'binary'
};
var wbout = XLSX.write(workbook, wopts);
var blob = new Blob([s2ab(wbout)], {type:"application/octet-stream"});
// Строка в ArrayBuffer
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;
}
return blob;
}
Получите объект blob выше, и вы можете загрузить его напрямую, см. Мой предыдущийJS всплывает диалоговое окно загрузкиИнкапсулирован внутриopenDownloadDialog
метод:
/**
* Общий метод открытия диалогового окна загрузки не тестировался на совместимость
* @param url-адрес загрузки, это также может быть объект blob, обязательно
* @param saveName имя файла сохранения, необязательно
*/
function openDownloadDialog(url, saveName)
{
if(typeof url == 'object' && url instanceof Blob)
{
url = URL.createObjectURL (url); // Создание адреса большого двоичного объекта
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // новый атрибут HTML5, укажите имя файла сохранения, суффикс не требуется, обратите внимание, что он не вступит в силу в режиме file: ///
var event;
if(window.MouseEvent) event = new MouseEvent('click');
else
{
event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event);
}
Таким образом, окончательная загрузка выглядит следующим образом:
// Передаем csv, и после выполнения появится окно загрузки
function exportExcel(csv) {
var sheet = csv2sheet(csv);
var blob = sheet2blob(sheet);
openDownloadDialog (blob, 'Export.xlsx');
}
3.2. Используйте официальные инструменты для создания
На самом деле, нам не нужно писать ни один из вышеперечисленных кодов. Чиновник предоставил нам готовые инструменты, в основном в том числе:
aoa_to_sheet
: Этот класс инструментов является наиболее мощным и практичным.Преобразование двумерного массива в лист автоматически обработает числовые, строковые, логические, даты и другие типы данных;table_to_sheet
: Поставить одинtable dom
Непосредственно преобразованный в лист, он будет автоматически распознанcolspan
сrowspan
И преобразовать его в соответствующую ячейку и объединить;json_to_sheet
: Преобразовать массив объектов в лист;
aoa_to_sheet
Пример:
var aoa = [
["Имя", "Пол", "Возраст", "Время регистрации"],
['Zhang San', 'Male', 18 лет, новое свидание ()],
[' ', ' ', 22, новая дата ()]
];
var sheet = XLSX.utils.aoa_to_sheet(aoa);
openDownloadDialog (sheet2blob (лист), 'Export.xlsx');
table_to_sheet
Еще проще, прямоXLSX.utils.table_to_sheet($('table')[0])
Может
3.3. Решение проблемы слияния ячеек
Вообще говоря, интерфейсное поколениеexcel
Вместоcsv
Основная цель — решить проблему, заключающуюся в том, что csv не может выполнить слияние ячеек. В противном случае было бы неплохо напрямую экспортировать файл csv. Зачем вводить несколько сотен килобайт плагинов.
Предположим, мы хотим сгенерировать файл Excel в следующем формате, гдеA1-C1
Чтобы объединить ячейки:
код показан ниже:
var aoa = [
['Основная информация', null, null, 'Другая информация'], // Особое внимание следует уделить резервированию 2 нулевых значений за объединенным местом
["Имя", "Пол", "Возраст", "Время регистрации"],
['Zhang San', 'Male', 18 лет, новое свидание ()],
[' ', ' ', 22, новая дата ()]
];
var sheet = XLSX.utils.aoa_to_sheet(aoa);
sheet['!merges'] = [
// Устанавливаем слияние ячеек A1-C1
{s: {r: 0, c: 0}, e: {r: 0, c: 2}}
];
openDownloadDialog (sheet2blob (sheet), 'Слияние ячеек example.xlsx');
Стоит обратить внимание на использование объединенных ячеек.null
Зарезервируйте место, иначе следующий контент (в этом примере четвертый столбецДополнительная информация
) Будет перезаписан.
3.4. Пользовательский стиль
Обычная версия не поддерживает определение шрифтов, цветов, цветов фона и т. Д., Вы можете использовать ее, если вам нужна эта функция.профессиональная версия, Вроде заряжено, потому что официальный сайт не видел адреса загрузки.
Персональный сайт:https://haoji.me
github:https://github.com/sxei
Сад блогов:http://www.cnblogs.com/liuxianan
авторское право © 2012-2018 одноклассник Xiaominggrapecity.com.cn/spreadjs/excel-online/content/index.html
Welcome to a tutorial on how to create an Excel file in Javascript. Yes, you read that right. We are referring to “browser Javascript”, and not the server-side NodeJS. The dark days have passed and it is actually possible to generate Excel files using client-side Javascript – Read on for the examples!
ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.
TLDR – QUICK SLIDES
Fullscreen Mode – Click Here
TABLE OF CONTENTS
DOWNLOAD & NOTES
Firstly, here is the download link to the example code as promised.
QUICK NOTES
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.
SCREENSHOT
EXAMPLE CODE DOWNLOAD
Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
All right, let us now get into the examples of generating an Excel file in Javascript.
EXAMPLE 1) GENERATE EXCEL FILE & FORCE DOWNLOAD
1A) THE HTML
1-create-excel.html
<!-- (A) LOAD SHEETJS FROM CDN -->
<!-- https://sheetjs.com/ -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<!-- (B) CLICK TO GENERATE DEMO EXCEL -->
<button id="demo">Download Demo Excel</button>
<!-- (C) JAVASCRIPT -->
document.getElementById("demo").onclick = () => { ... };
Yep, that is pretty much everything we need to drive the example.
- Load SheetJS from CDNJS, this library is required to create the Excel file. Will leave a link in the extras section below to their full documentation.
- A demo button to start generating the Excel file.
- Generate the Excel file when the button is clicked.
1B) DUMMY DATA
1-create-excel.html
// (C1) DUMMY DATA
var data = [
["Joa Doe", "joa@doe.com"],
["Job Doe", "job@doe.com"],
["Joe Doe", "joe@doe.com"],
["Jon Doe", "jon@doe.com"],
["Joy Doe", "joy@doe.com"]
];
For the Javascript, we will first start by defining a nested array of dummy data. Don’t think it needs a lot of explanation, this will get “converted” into rows and columns in the Excel file.
1C) CREATE A NEW EXCEL OBJECT
1-create-excel.html
// (C2) CREATE NEW EXCEL "FILE"
var workbook = XLSX.utils.book_new(),
worksheet = XLSX.utils.aoa_to_sheet(data);
workbook.SheetNames.push("First");
workbook.Sheets["First"] = worksheet;
This should be pretty self-explanatory for the folks who already know Excel well, but for the sake of those who are new:
- A “workbook” is simply “the entire Excel file”.
- A “worksheet” is a table within a workbook.
- A workbook can contain multiple worksheets.
So what this section is doing:
workbook = XLSX.utils.book_new()
Creates a new Excel workbook.worksheet = XLSX.utils.aoa_to_sheet(data)
Creates a new worksheet, using the dummy data array above.workbook.SheetNames.push("First")
andworkbook.Sheets["First"] = worksheet
Attach the worksheet to the workbook.
1D) FORCE DOWNLOAD
1-create-excel.html
// (C3) "FORCE DOWNLOAD" XLSX FILE
XLSX.writeFile(workbook, "demo.xlsx");
Horray, we now have an Excel object. All that’s left is to “force download” the Excel file, and allow the user to save it.
EXAMPLE 2) GENERATE EXCEL FILE & UPLOAD TO SERVER
2A) UPLOAD GENERATED EXCEL FILE
2a-upload-excel.html
// (C3) TO BLOB
var xlsblob = new Blob(
[new Uint8Array(XLSX.write(workbook, { bookType: "xlsx", type: "array" }))],
{type:"application/octet-stream"}
);
// (C4) FORM DATA
var data = new FormData();
data.append("xls", xlsblob, "demo.xlsx");
// (C5) UPLOAD TO SERVER
fetch("2b-upload.php", { method: "POST", body: data })
.then(res => res.text())
.then(txt => console.log(txt));
This is an alternative if you want to upload the generated Excel file to the server instead.
- (C3) Instead of “forcing a download”, we turn the workbook into a blob (binary object).
- (C4) Attach the Excel blob as form data.
- (C5) Send the Excel blob to the server… Otherwise also known as “file upload”.
2B) SAVE THE UPLOADED EXCEL FILE
2b-upload.php
<?php
echo move_uploaded_file(
$_FILES["xls"]["tmp_name"],
__DIR__ . DIRECTORY_SEPARATOR . $_FILES["xls"]["name"]
) ? "OK" : "ERROR" ;
On the server side, we simply save the uploaded Excel file like a “normal file upload”. This is a simple “save uploaded file” snippet in PHP.
EFFICIENCY & PERFORMANCE
Just a quick note that we are holding an entire Excel file in the memory with this example… This will work great for small to medium Excel files, but the massive ones are going to run into performance issues and memory limits. You may want to implement some sort of restrictions on the maximum amount of data, or look at server-side alternatives with streaming.
COMPATIBILITY CHECKS
- Arrow Functions – CanIUse
- Array Buffer – CanIUse
- Uint8Array – Can I Use
This example will work on all modern “Grade A” browsers.
LINKS & REFERENCES
- SheetJS Documentation
- Export From MySQL Database To Excel In NodeJS – Code Boxx
INFOGRAPHICS CHEAT SHEET
THE END
Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!