• 在Vue.js中使用xlsx组件实现Excel导出


            在现代Web应用程序中,数据导出到Excel格式是一项常见的需求。Vue.js是一种流行的JavaScript框架,允许我们构建动态的前端应用程序。本文将介绍如何使用Vue.js和xlsx组件轻松实现Excel数据导出功能。

    1、项目设置

            首先,在控制台执行以下命令安装xlsx组件;

    1. npm install xlsx --save
    2. yarn add xlsx --save

            然后,在vue项目中引入xls组件;

    import XLSX from 'xlsx';

    2、准备数据

            要导出到Excel,您需要有数据。您可以使用本地数据或从API获取数据。在本示例中,我们将使用本地数据:

    1. exportData: [
    2. { name: "John", age: 30, city: "New York" },
    3. { name: "Alice", age: 25, city: "Los Angeles" },
    4. { name: "Bob", age: 35, city: "Chicago" }
    5. ]

    3、实现导出功能

            创建导出到Excel的方法。这个方法将触发Excel文件的生成和下载:

    1. exportToExcel() {
    2. const worksheet = XLSX.utils.json_to_sheet(this.exportData);
    3. const workbook = XLSX.utils.book_new();
    4. XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
    5. XLSX.writeFile(workbook, "exported-data.xlsx");
    6. }

            这个方法使用xlsx组件将数据转换为Excel工作表,然后创建一个工作簿并将工作表添加到工作簿中。最后,它使用XLSX.writeFile方法将工作簿保存为名为"exported-data.xlsx"的Excel文件。

    4、设置列宽自适应

            根据导出数据的长度,通过遍历计算每列的最大长度,然后通过worksheet['!cols']方法设置每列宽度;

    1. // 设置列宽
    2. exportData.forEach((row, rowIndex) => {
    3. row.forEach((cell, cellIndex) => {
    4. const list = arrData.map(item => {
    5. const val = item[cellIndex] as string;
    6. if(isEmptyString(val)){
    7. return 1;
    8. } else if(val.toString().charCodeAt(0) > 255){ // 判断是否有中文
    9. return val.toString().length * 2
    10. } else{
    11. return val.toString().length;
    12. }
    13. });
    14. const maxLength = Math.max(...list);
    15. const width = maxLength * 1.1; // 根据实际内容长度自动调整列宽
    16. if(!worksheet["!cols"]) worksheet["!cols"] = [];
    17. if(!worksheet["!cols"][cellIndex]) worksheet["!cols"][cellIndex] = {wch: 8};
    18. worksheet['!cols'][cellIndex].wch = width; // 使用worksheet的 '!cols' 来设置列宽
    19. });
    20. });

    5、设置合并单元格

            通过worksheet["!merges"]方法可以设置合并单元格;

    1. // 合并单元格
    2. merges.forEach((item) => {
    3. if(!worksheet["!merges"]){
    4. worksheet["!merges"] = [];
    5. };
    6. worksheet["!merges"].push(item);
    7. // worksheet["!merges"].push({
    8. // s: { r: 2, c: 1 }, // s ("start"): c = 1 r = 2 -> "B3"
    9. // e: { r: 3, c: 4 } // e ("end"): c = 4 r = 3 -> "E4"
    10. // });
    11. });

    6、设置导出Excel表格的样式

            xlsx组件库是不支持设置Excel表格样式的,但是可以通过引入xlsx-style-vite组件库来实现样式的设置;然后通过file-saver导出文件;

    6.1 安装并引入xlsx-style-vite和file-saver组件
    1. yarn add xlsx-style-vite --save
    2. yarn add file-saver --save
    1. import XLSXStyle from 'xlsx-style-vite';
    2. import XLSX_SAVE from 'file-saver';

    其中 xlsx-style-vite组件是xlsx-style组件的vite版本,用于解决在vite下引入xlsx-style异常的问题;

    6.2 设置单元格居中

           遍历所有单元格,然后通过worksheet[column].s方法设置每个单元格的样式;

    1. exportData.forEach((row, rowIndex) => {
    2. row.forEach((cell, cellIndex) => {
    3. // 设置所有单元格居中
    4. let column = utils.encode_cell({c: cellIndex, r: rowIndex});
    5. worksheet[column].s = {
    6. alignment: {
    7. horizontal: 'center',
    8. vertical: 'center',
    9. wrapText: false, // 自动换行
    10. },
    11. }
    12. });
    13. });
    6.3 设置单元格背景色和字体
    1. exportData.forEach((row, rowIndex) => {
    2. row.forEach((cell, cellIndex) => {
    3. // 设置所有单元格居中
    4. let column = utils.encode_cell({c: cellIndex, r: rowIndex});
    5. if(worksheet[column]){
    6. // 设置背景色、加粗展示
    7. worksheet[column].s = {
    8. font: {
    9. name: "微软雅黑",
    10. sz: 16,
    11. color: { rgb: "000000" },
    12. bold: true,
    13. italic: false,
    14. underline: false,
    15. },
    16. fill: {
    17. fgColor: { rgb: "C5D9F1" },
    18. },
    19. alignment: {
    20. horizontal: 'center',
    21. vertical: 'center',
    22. wrapText: false, // 自动换行
    23. },
    24. }
    25. }
    26. }
    27. });
    28. });
    6.4 设置单元格边框
    1. //单元格外侧框线
    2. const borderAll = {
    3. top: {
    4. style: "thin",
    5. },
    6. bottom: {
    7. style: "thin",
    8. },
    9. left: {
    10. style: "thin",
    11. },
    12. right: {
    13. style: "thin",
    14. },
    15. };
    16. // 设置单元格边框
    17. arrData.forEach((row, rowIndex) => {
    18. row.forEach((cell, cellIndex) => {
    19. let column = utils.encode_cell({c: cellIndex, r: rowIndex});
    20. if(worksheet[column]){
    21. worksheet[column].s = {
    22. border: borderAll,
    23. }
    24. }
    25. }
    26. });
    27. });
    6.5 导出文件

           必须通过file-saver组件导出Excel文件,不能通过xlsx组件的writeFile方法导出文件,否则样式无法生效;

    1. const wbout = XLSXStyle.write(workbook, {
    2. type: 'binary',
    3. bookType: 'xlsx',
    4. });
    5. XLSX_SAVE.saveAs(
    6. new Blob([s2ab(wbout)], {
    7. type: 'application/octet-stream',
    8. }),
    9. 'exported-data.xlsx',
    10. );
    11. // 数据转换
    12. function s2ab(s) {
    13. var buf = new ArrayBuffer(s.length);
    14. var view = new Uint8Array(buf);
    15. for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    16. return buf;
    17. }

    7、完整代码示例

    1. import * as xlsx from 'xlsx';
    2. import type { WorkBook } from 'xlsx';
    3. import type { JsonToSheet, AoAToSheet } from './typing';
    4. import XLSXStyle from 'xlsx-style-vite';
    5. import XLSX_SAVE from 'file-saver';
    6. import { isEmptyString } from '@/utils/table';
    7. const { utils, writeFile } = xlsx;
    8. const DEF_FILE_NAME = 'excel-list.xlsx';
    9. export function aoaToSheetXlsx({
    10. data,
    11. header,
    12. filename = DEF_FILE_NAME,
    13. write2excelOpts = { bookType: 'xlsx' },
    14. merges = [],
    15. }: AoAToSheet) {
    16. const arrData = [...data];
    17. if (header) {
    18. arrData.unshift(header);
    19. }
    20. const worksheet = utils.aoa_to_sheet(arrData);
    21. /* add worksheet to workbook */
    22. const workbook: WorkBook = {
    23. SheetNames: [filename],
    24. Sheets: {
    25. [filename]: worksheet,
    26. },
    27. };
    28. //单元格外侧框线
    29. const borderAll = {
    30. top: {
    31. style: "thin",
    32. },
    33. bottom: {
    34. style: "thin",
    35. },
    36. left: {
    37. style: "thin",
    38. },
    39. right: {
    40. style: "thin",
    41. },
    42. };
    43. // 设置列宽
    44. arrData.forEach((row, rowIndex) => {
    45. row.forEach((cell, cellIndex) => {
    46. const list = arrData.map(item => {
    47. const val = item[cellIndex] as string;
    48. if(isEmptyString(val)){
    49. return 1;
    50. } else if(val.toString().charCodeAt(0) > 255){ // 判断是否有中文
    51. return val.toString().length * 2
    52. } else{
    53. return val.toString().length;
    54. }
    55. });
    56. const maxLength = Math.max(...list);
    57. const width = maxLength * 1.1; // 根据实际内容长度自动调整列宽
    58. if(!worksheet["!cols"]) worksheet["!cols"] = [];
    59. if(!worksheet["!cols"][cellIndex]) worksheet["!cols"][cellIndex] = {wch: 8};
    60. worksheet['!cols'][cellIndex].wch = width; // 使用worksheet的 '!cols' 来设置列宽
    61. // 设置所有单元格居中
    62. let column = utils.encode_cell({c: cellIndex, r: rowIndex});
    63. if(worksheet[column]){
    64. if(rowIndex === 0) { // 标题行设置背景色、加粗展示
    65. worksheet[column].s = {
    66. border: borderAll,
    67. font: {
    68. // name: "微软雅黑",
    69. // sz: 16,
    70. color: { rgb: "000000" },
    71. bold: true,
    72. italic: false,
    73. underline: false,
    74. },
    75. fill: {
    76. fgColor: { rgb: "C5D9F1" },
    77. },
    78. alignment: {
    79. horizontal: 'center',
    80. vertical: 'center',
    81. wrapText: false, // 自动换行
    82. },
    83. }
    84. } else {
    85. worksheet[column].s = {
    86. alignment: {
    87. horizontal: 'center',
    88. vertical: 'center',
    89. wrapText: false, // 自动换行
    90. },
    91. }
    92. }
    93. }
    94. });
    95. });
    96. // 合并单元格
    97. merges.forEach((item) => {
    98. if(!worksheet["!merges"]){
    99. worksheet["!merges"] = [];
    100. };
    101. worksheet["!merges"].push(item);
    102. // worksheet["!merges"].push({
    103. // s: { r: 2, c: 1 }, // s ("start"): c = 1 r = 2 -> "B3"
    104. // e: { r: 3, c: 4 } // e ("end"): c = 4 r = 3 -> "E4"
    105. // });
    106. });
    107. const wbout = XLSXStyle.write(workbook, {
    108. type: 'binary',
    109. bookType: 'xlsx',
    110. });
    111. XLSX_SAVE.saveAs(
    112. new Blob([s2ab(wbout)], {
    113. type: 'application/octet-stream',
    114. }),
    115. `${filename}.${write2excelOpts.bookType}`,
    116. );
    117. /* output format determined by filename */
    118. // writeFile(workbook, filename, write2excelOpts);
    119. /* at this point, out.xlsb will have been downloaded */
    120. }
    121. // 数据转换
    122. function s2ab(s) {
    123. var buf = new ArrayBuffer(s.length);
    124. var view = new Uint8Array(buf);
    125. for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    126. return buf;
    127. }

    新时代农民工

  • 相关阅读:
    进化:元宇宙明天的主题
    “深入理解机器学习性能评估指标:TP、TN、FP、FN、精确率、召回率、准确率、F1-score和mAP”
    vue3接口、数据懒加载,回滚不重复加载
    零基础重庆自考本科行政管理难吗?
    JavaScript Promise
    layer 弹框让按钮取消自动获取焦点
    react 可视化编辑器1
    C++提高:04STL- 函数对象
    Ubuntu系统apt添加第三方PPA源
    go 获取文件类型
  • 原文地址:https://blog.csdn.net/sg_knight/article/details/134003709