Формирование простого Excel на js
Иногда возникает необходимость сохранить отображаемую таблицу в Excel.
В таком случае HTML-код таблицы можно сохранить в файл и выдать сохранение как .xls.
При открытии HTML, сохранённого как .xls, Excel будет выдавать уведомление о том, что файл небезопасен или повреждён.
Однако, если подтвердить открытие, таблица откроется в Excel-файле.
Расширение файла должно быть .xls. Сохранить в .xlsx таким способом не получится.
Описанные ниже методы не создают полноценный Excel-файл, а лишь позволяют передать Excel фрагмент HTML-разметки, который он сможет открыть как таблицу с предупреждениями. Для создания полноценного Excel-файла необходимо использовать специализированные библиотеки.
Сохранение HTML-кода таблицы в .xls
Чтобы в Excel корректно отображались символы, необходимо указать кодировку и добавить в начало файла корректный BOM-символ:
<button id="saveExcel">Скачать Excel</button>
<table id="table"></table>
<script>
document.getElementById('saveExcel').addEventListener('click', () => {
const table = document.getElementById('table');
const blob = new Blob(
[ new Uint8Array([0xEF, 0xBB, 0xBF]), table.outerHTML ],
{ type: 'application/excel;charset=utf-8' }
);
const anchor = document.createElement('a');
document.body.appendChild(anchor);
const url = window.URL.createObjectURL(blob);
anchor.href = url;
anchor.download = 'Excel file name.xls';
anchor.click();
anchor.remove();
window.URL.revokeObjectURL(url);
});
</script>
Вписывание стилей в код
При генерации кода таблицы с помощью Vue пропускаются теги <style>, <script>.
Внедрение специальных стилей можно обойти используя <component is="style"/>:
<template>
<div ref="excelTable">
<component is="style">
.string { mso-number-format: "@"; }
.number { mso-number-format: "#\,##0.00"; }
br { mso-data-placement:same-cell; }
</component>
<table></table>
</div>
</template>
Стили для отображения данных в Excel
<style>
.string { mso-number-format: "@"; }
.number { mso-number-format: "#\,##0.00"; }
.integer { mso-number-format: "0"; }
br { mso-data-placement: same-cell; } /* Перенос строки */
</style>
Excel через промежуточный XML
У Excel файла, созданного предыдущим образом, не будет привычной сеточной разметки.
Для привычного отображения файла в Excel необходимо создать документ специального вида:
<html
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40"
>
<head>
<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>sheetName</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
</head>
<body>
<table></table>
</body>
</html>
Обратите внимание на узел <x:Name>sheetName</x:Name>. С помощью этого узла можно указать название листа для Excel.
В LibreOffice этот узел не читается. Поэтому для совместимости вся строка заключена в [if gte mso 9].
Так же преимуществом данного способа является возможность указать кодировку без использования BOM-символов, достаточно в <head> добавить <meta>:
Пример
/**
* @param table HTML код таблицы, которую надо выгрузить в Excel
* @param sheetName Заголовок листа для Excel
*/
const generateExcelDocument = (table, sheetName = '') => `
<html
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40"
>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>${sheetName}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
</head>
<body>${table}</body>
</html>
`;
document.getElementById('saveExcel').addEventListener('click', () => {
const blob = new Blob(
[ generateExcelDocument(document.getElementById('table').outerHTML, 'Список товаров') ],
{ type: 'application/vnd.ms-excel;charset=utf-8' }
);
const anchor = document.createElement('a');
document.body.appendChild(anchor);
const url = window.URL.createObjectURL(blob);
anchor.href = url;
anchor.download = 'Excel file name.xls';
anchor.click();
anchor.remove();
window.URL.revokeObjectURL(url);
});
Внедрение стилей в Excel файл
Чтоб стили <style> корректно обрабатывались Excel'ем - они должны быть помещены в раздел <head> полученного документа.
Excel не поддерживает множество классов на элементе. Если написать так - Excel не распознает ни одного класса. Можно указать только один класс
<!-- в таком виде ни один из классов не будет распознан -->
<td class="first second"></td>
<!-- корректный способ указать класс -->
<td class="general"></td>
Так же надо учитывать, что некоторые единицы в Excel отличаются от html.
Например, у размера шрифта вместо пикселей px указываются пойнты pt (типографический пункт).