在现代Web应用程序中,数据导出到Excel格式是一项常见的需求。Vue.js是一种流行的JavaScript框架,允许我们构建动态的前端应用程序。本文将介绍如何使用Vue.js和xlsx组件轻松实现Excel数据导出功能。
首先,在控制台执行以下命令安装xlsx组件;
- npm install xlsx --save
-
- 或
-
- yarn add xlsx --save
然后,在vue项目中引入xls组件;
import XLSX from 'xlsx';
要导出到Excel,您需要有数据。您可以使用本地数据或从API获取数据。在本示例中,我们将使用本地数据:
-
- exportData: [
- { name: "John", age: 30, city: "New York" },
- { name: "Alice", age: 25, city: "Los Angeles" },
- { name: "Bob", age: 35, city: "Chicago" }
- ]
-
创建导出到Excel的方法。这个方法将触发Excel文件的生成和下载:
- exportToExcel() {
- const worksheet = XLSX.utils.json_to_sheet(this.exportData);
- const workbook = XLSX.utils.book_new();
- XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
- XLSX.writeFile(workbook, "exported-data.xlsx");
- }
这个方法使用xlsx组件将数据转换为Excel工作表,然后创建一个工作簿并将工作表添加到工作簿中。最后,它使用XLSX.writeFile方法将工作簿保存为名为"exported-data.xlsx"的Excel文件。
根据导出数据的长度,通过遍历计算每列的最大长度,然后通过worksheet['!cols']方法设置每列宽度;
- // 设置列宽
- exportData.forEach((row, rowIndex) => {
- row.forEach((cell, cellIndex) => {
- const list = arrData.map(item => {
- const val = item[cellIndex] as string;
- if(isEmptyString(val)){
- return 1;
- } else if(val.toString().charCodeAt(0) > 255){ // 判断是否有中文
- return val.toString().length * 2
- } else{
- return val.toString().length;
- }
- });
- const maxLength = Math.max(...list);
- const width = maxLength * 1.1; // 根据实际内容长度自动调整列宽
- if(!worksheet["!cols"]) worksheet["!cols"] = [];
- if(!worksheet["!cols"][cellIndex]) worksheet["!cols"][cellIndex] = {wch: 8};
- worksheet['!cols'][cellIndex].wch = width; // 使用worksheet的 '!cols' 来设置列宽
- });
- });
通过worksheet["!merges"]方法可以设置合并单元格;
- // 合并单元格
- merges.forEach((item) => {
- if(!worksheet["!merges"]){
- worksheet["!merges"] = [];
- };
- worksheet["!merges"].push(item);
- // worksheet["!merges"].push({
- // s: { r: 2, c: 1 }, // s ("start"): c = 1 r = 2 -> "B3"
- // e: { r: 3, c: 4 } // e ("end"): c = 4 r = 3 -> "E4"
- // });
- });
xlsx组件库是不支持设置Excel表格样式的,但是可以通过引入xlsx-style-vite组件库来实现样式的设置;然后通过file-saver导出文件;
- yarn add xlsx-style-vite --save
-
- yarn add file-saver --save
- import XLSXStyle from 'xlsx-style-vite';
- import XLSX_SAVE from 'file-saver';
其中 xlsx-style-vite组件是xlsx-style组件的vite版本,用于解决在vite下引入xlsx-style异常的问题;
遍历所有单元格,然后通过worksheet[column].s方法设置每个单元格的样式;
- exportData.forEach((row, rowIndex) => {
- row.forEach((cell, cellIndex) => {
- // 设置所有单元格居中
- let column = utils.encode_cell({c: cellIndex, r: rowIndex});
- worksheet[column].s = {
- alignment: {
- horizontal: 'center',
- vertical: 'center',
- wrapText: false, // 自动换行
- },
- }
- });
- });
- exportData.forEach((row, rowIndex) => {
- row.forEach((cell, cellIndex) => {
- // 设置所有单元格居中
- let column = utils.encode_cell({c: cellIndex, r: rowIndex});
- if(worksheet[column]){
- // 设置背景色、加粗展示
- worksheet[column].s = {
- font: {
- name: "微软雅黑",
- sz: 16,
- color: { rgb: "000000" },
- bold: true,
- italic: false,
- underline: false,
- },
- fill: {
- fgColor: { rgb: "C5D9F1" },
- },
- alignment: {
- horizontal: 'center',
- vertical: 'center',
- wrapText: false, // 自动换行
- },
- }
- }
- }
- });
- });
- //单元格外侧框线
- const borderAll = {
- top: {
- style: "thin",
- },
- bottom: {
- style: "thin",
- },
- left: {
- style: "thin",
- },
- right: {
- style: "thin",
- },
- };
-
- // 设置单元格边框
- arrData.forEach((row, rowIndex) => {
- row.forEach((cell, cellIndex) => {
- let column = utils.encode_cell({c: cellIndex, r: rowIndex});
- if(worksheet[column]){
- worksheet[column].s = {
- border: borderAll,
- }
- }
- }
- });
- });
必须通过file-saver组件导出Excel文件,不能通过xlsx组件的writeFile方法导出文件,否则样式无法生效;
- const wbout = XLSXStyle.write(workbook, {
- type: 'binary',
- bookType: 'xlsx',
- });
- XLSX_SAVE.saveAs(
- new Blob([s2ab(wbout)], {
- type: 'application/octet-stream',
- }),
- 'exported-data.xlsx',
- );
-
-
- // 数据转换
- 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;
- }
- import * as xlsx from 'xlsx';
- import type { WorkBook } from 'xlsx';
- import type { JsonToSheet, AoAToSheet } from './typing';
- import XLSXStyle from 'xlsx-style-vite';
- import XLSX_SAVE from 'file-saver';
- import { isEmptyString } from '@/utils/table';
-
- const { utils, writeFile } = xlsx;
-
- const DEF_FILE_NAME = 'excel-list.xlsx';
-
- export function aoaToSheetXlsx
({ - data,
- header,
- filename = DEF_FILE_NAME,
- write2excelOpts = { bookType: 'xlsx' },
- merges = [],
- }: AoAToSheet
) { - const arrData = [...data];
- if (header) {
- arrData.unshift(header);
- }
-
- const worksheet = utils.aoa_to_sheet(arrData);
-
- /* add worksheet to workbook */
- const workbook: WorkBook = {
- SheetNames: [filename],
- Sheets: {
- [filename]: worksheet,
- },
- };
-
- //单元格外侧框线
- const borderAll = {
- top: {
- style: "thin",
- },
- bottom: {
- style: "thin",
- },
- left: {
- style: "thin",
- },
- right: {
- style: "thin",
- },
- };
-
- // 设置列宽
- arrData.forEach((row, rowIndex) => {
- row.forEach((cell, cellIndex) => {
- const list = arrData.map(item => {
- const val = item[cellIndex] as string;
- if(isEmptyString(val)){
- return 1;
- } else if(val.toString().charCodeAt(0) > 255){ // 判断是否有中文
- return val.toString().length * 2
- } else{
- return val.toString().length;
- }
- });
- const maxLength = Math.max(...list);
- const width = maxLength * 1.1; // 根据实际内容长度自动调整列宽
- if(!worksheet["!cols"]) worksheet["!cols"] = [];
- if(!worksheet["!cols"][cellIndex]) worksheet["!cols"][cellIndex] = {wch: 8};
- worksheet['!cols'][cellIndex].wch = width; // 使用worksheet的 '!cols' 来设置列宽
-
- // 设置所有单元格居中
- let column = utils.encode_cell({c: cellIndex, r: rowIndex});
- if(worksheet[column]){
- if(rowIndex === 0) { // 标题行设置背景色、加粗展示
- worksheet[column].s = {
- border: borderAll,
- font: {
- // name: "微软雅黑",
- // sz: 16,
- color: { rgb: "000000" },
- bold: true,
- italic: false,
- underline: false,
- },
- fill: {
- fgColor: { rgb: "C5D9F1" },
- },
- alignment: {
- horizontal: 'center',
- vertical: 'center',
- wrapText: false, // 自动换行
- },
- }
- } else {
- worksheet[column].s = {
- alignment: {
- horizontal: 'center',
- vertical: 'center',
- wrapText: false, // 自动换行
- },
- }
- }
- }
- });
- });
-
- // 合并单元格
- merges.forEach((item) => {
- if(!worksheet["!merges"]){
- worksheet["!merges"] = [];
- };
- worksheet["!merges"].push(item);
- // worksheet["!merges"].push({
- // s: { r: 2, c: 1 }, // s ("start"): c = 1 r = 2 -> "B3"
- // e: { r: 3, c: 4 } // e ("end"): c = 4 r = 3 -> "E4"
- // });
- });
-
- const wbout = XLSXStyle.write(workbook, {
- type: 'binary',
- bookType: 'xlsx',
- });
- XLSX_SAVE.saveAs(
- new Blob([s2ab(wbout)], {
- type: 'application/octet-stream',
- }),
- `${filename}.${write2excelOpts.bookType}`,
- );
-
- /* output format determined by filename */
- // writeFile(workbook, filename, write2excelOpts);
- /* at this point, out.xlsb will have been downloaded */
- }
-
- // 数据转换
- 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;
- }