在Angular中将数据导出到Excel和CSV
在开发Web应用程序时,我们经常需要允许用户将数据下载为他们指定的格式。其中一项需求是允许用户将数据导出为电子表格(Excel)或CSV文件。
这是一个非常常见的用例,因此我决定创建一个分步指南,帮助大家轻松完成此操作。我们将讨论导出到以下两个主要区域:
📝 注意:
我已经在 GitHub 上创建了一个关于此实现的仓库。
idris-rampurawala / ng-数据导出
演示如何使用 Angular 10 实现将数据导出到 Excel 和 CSV 的导出服务
导出到 Excel
将数据导出到 Excel 的功能不仅为用户提供了强大的功能,而且还能帮助我们创建一系列其他相关功能,从而帮助用户更好地理解数据。那么我们该如何开始呢?正如您所料,我们有一个 npm 包可以处理这个问题——xlsx (也称为 sheetjs) 😁
安装依赖项
# installing xlsx package
$ npm install xlsx
# installing file-saver - a solution to saving files on the client-side
$ npm install file-saver
创建出口服务
在 Angular 中,创建常用功能的一种方法是为其创建服务。因此,我们创建了一个导出服务,该服务将包含导出所有类型信息(本文中为 Excel 和 CSV 格式)的功能。
使用 xlsx
xlsx它提供了一套非常丰富的实用工具,用于创建或解析电子表格。为了简单起见,我们这里只重点介绍其中几个实用工具。
1️⃣ 导出 HTML 表格
如果要将数据导出HTML table到 Excel,这非常简单,因为xlsxExcel 提供了相应的工具。假设我们有一个表格👇
<!-- app.component.html -->
<table class="table table-sm" #userTable> <!-- we will make use of this angular var as element reference -->
<thead class="thead-dark">
<tr>
<th scope="col">#</th>
...
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td scope="row">{{ user.id }}</td>
...
</tr>
<tr>
</tbody>
</table>
现在,我们可以创建一个service函数来接收这个值HTML element reference并从中生成 Excel 文件(使用<thead>和<tbody>)。
/* export.service.ts */
import { Injectable, ElementRef } from '@angular/core';
import * as FileSaver from 'file-saver';
import * as XLSX from 'xlsx';
const EXCEL_EXTENSION = '.xlsx';
@Injectable()
export class ExportService {
constructor() { }
/**
* Creates excel from the table element reference.
*
* @param element DOM table element reference.
* @param fileName filename to save as.
*/
public exportTableElmToExcel(element: ElementRef, fileName: string): void {
const ws: XLSX.WorkSheet = XLSX.utils.table_to_sheet(element.nativeElement);
// generate workbook and add the worksheet
const workbook: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, ws, 'Sheet1');
// save to file
XLSX.writeFile(workbook, `${fileName}${EXCEL_EXTENSION}`);
}
...
}
我们component.ts只需创建一个处理程序,export button尝试将文件保存为客户端计算机上的 Excel 文件即可。
/* app.component.ts */
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { ExcelJson } from './interfaces/excel-json.interface';
import { ExportService } from './services/export.service';
...
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
...
/* the table reference */
@ViewChild('userTable') userTable: ElementRef;
...
constructor(
private exportService: ExportService
) { }
ngOnInit(): void {
...
}
/**
* Function prepares data to pass to export service to create excel from Table DOM reference
*
*/
exportElmToExcel(): void {
this.exportService.exportTableElmToExcel(this.userTable, 'user_data');
}
...
}
这很简单,对吧?😆 如果我们想导出更复杂的数据呢?🙄 让我们一起来看看👇
2️⃣ 导出更复杂的数据
xlsx它还提供了各种其他实用工具来自定义 Excel 中的数据(使用 Excel 列名进行标识)。例如,我曾在某个项目中创建了一个函数,用于将整个仪表板数据导出到 Excel。让我们也创建一个类似的A, B, C..函数。service
/* export.service.ts */
...
/**
* Creates XLSX option from the Json data. Use this to customize the sheet by adding arbitrary rows and columns.
*
* @param json Json data to create xlsx.
* @param fileName filename to save as.
*/
public exportJsonToExcel(json: ExcelJson[], fileName: string): void {
// inserting first blank row
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(
json[0].data,
this.getOptions(json[0])
);
for (let i = 1, length = json.length; i < length; i++) {
// adding a dummy row for separation
XLSX.utils.sheet_add_json(
worksheet,
[{}],
this.getOptions(
{
data: [],
skipHeader: true
}, -1)
);
XLSX.utils.sheet_add_json(
worksheet,
json[i].data,
this.getOptions(json[i], -1)
);
}
const workbook: XLSX.WorkBook = { Sheets: { Sheet1: worksheet }, SheetNames: ['Sheet1'] };
// save to file
XLSX.writeFile(workbook, `${fileName}${EXCEL_EXTENSION}`);
}
/**
* Creates the XLSX option from the data.
*
* @param json Json data to create xlsx.
* @param origin XLSX option origin.
* @returns options XLSX options.
*/
private getOptions(json: ExcelJson, origin?: number): any {
// adding actual data
const options = {
skipHeader: true,
origin: -1,
header: []
};
options.skipHeader = json.skipHeader ? json.skipHeader : false;
if (!options.skipHeader && json.header && json.header.length) {
options.header = json.header;
}
if (origin) {
options.origin = origin ? origin : -1;
}
return options;
}
...
然后component.ts,我们创建所需格式的数据xlsx,以便将其传递给此服务函数。
/* app.component.ts */
...
/**
* Function prepares data to pass to export service to create excel from Json
*
*/
exportToExcel(): void {
const edata: Array<ExcelJson> = [];
const udt: ExcelJson = {
data: [
{ A: 'User Data' }, // title
{ A: '#', B: 'First Name', C: 'Last Name', D: 'Handle' }, // table header
],
skipHeader: true
};
this.users.forEach(user => {
udt.data.push({
A: user.id,
B: user.firstName,
C: user.lastName,
D: user.handle
});
});
edata.push(udt);
// adding more data just to show "how we can keep on adding more data"
const bd = {
data: [
// chart title
{ A: 'Some more data', B: '' },
{ A: '#', B: 'First Name', C: 'Last Name', D: 'Handle' }, // table header
],
skipHeader: true
};
this.users.forEach(user => {
bd.data.push({
A: String(user.id),
B: user.firstName,
C: user.lastName,
D: user.handle
});
});
edata.push(bd);
this.exportService.exportJsonToExcel(edata, 'user_data_customized');
}
...
解释
感到困惑?😕 让我解释一下我们刚才做了什么。
xlsx(或电子表格)有一个workbook(这是一个实际的文件),我们可以在其中sheets添加多个。xlsx它提供了一个实用函数sheet_add_json(),可以将对象数组转换为带有额外 xlsx 选项的 Excel 数据。因此,我们为其创建了一个包装器,service通过该包装器可以传递具有不同 xlsx 选项的多个对象。这样,我们的导出服务就处理了复杂性,我们只需要创建一个对象数组传递给它即可。xlsx期望对象数组的形式为{cell: value },因此{A: 'value'}意味着我们要将其放入Excel 的value单元格(列)中。AskipHeader目的是跳过传递给函数的对象中自动生成的标头。sheet_add_json()origin: -1是将数据追加到工作表的底部,从第一列开始。- 此外,
ExcelJson还有一个自定义接口(是我创建的),用于定义服务函数期望的数据类型。它代表一个有效的对象数据xlsx。
有关更多信息,请阅读xlsx文档和github 上的示例实现。
如何设置Excel样式?🧐
xlsx其开源版本不提供样式设置。您可以选择其他方案pro version来获得样式设置和专门的支持。
或者,xlsx-style是其一个分支,xlsx它在其基础上提供了样式。
另一个非常流行的替代方案xlsx是ExcelJS。它也包含了样式功能,但与相比,提供的实用功能较少xlsx。
导出为 CSV
现在我们继续导出的第二部分,即 CSV 文件。
别担心😟,这很简单。我们只需要在代码中添加一个函数,export service该函数接受一个对象数组和一个列标题,然后根据数组内容创建一个 CSV 文件。
/* export.service.ts */
...
/**
* Saves the file on the client's machine via FileSaver library.
*
* @param buffer The data that need to be saved.
* @param fileName File name to save as.
* @param fileType File type to save as.
*/
private saveAsFile(buffer: any, fileName: string, fileType: string): void {
const data: Blob = new Blob([buffer], { type: fileType });
FileSaver.saveAs(data, fileName);
}
/**
* Creates an array of data to CSV. It will automatically generate a title row based on object keys.
*
* @param rows array of data to be converted to CSV.
* @param fileName filename to save as.
* @param columns array of object properties to convert to CSV. If skipped, then all object properties will be used for CSV.
*/
public exportToCsv(rows: object[], fileName: string, columns?: string[]): string {
if (!rows || !rows.length) {
return;
}
const separator = ',';
const keys = Object.keys(rows[0]).filter(k => {
if (columns?.length) {
return columns.includes(k);
} else {
return true;
}
});
const csvContent =
keys.join(separator) +
'\n' +
rows.map(row => {
return keys.map(k => {
let cell = row[k] === null || row[k] === undefined ? '' : row[k];
cell = cell instanceof Date
? cell.toLocaleString()
: cell.toString().replace(/"/g, '""');
if (cell.search(/("|,|\n)/g) >= 0) {
cell = `"${cell}"`;
}
return cell;
}).join(separator);
}).join('\n');
this.saveAsFile(csvContent, `${fileName}${CSV_EXTENSION}`, CSV_TYPE);
}
...
这段代码几乎一目了然🤓,它检查传入的数据中是否存在指定列的数据,并据此生成一个 CSV 文件。我们可以,根据需要随时更改分隔符。需要file-saver包才能将文件保存到客户端计算机上。
是不是很简单?🙌 你可以查看我的GitHub 代码库,那里有本文的完整实现。
如果您觉得这篇文章有用或有任何建议,欢迎留言。如果您喜欢我的帖子,也别忘了点赞❤️或🦄哦!
下次见!😋
文章来源:https://dev.to/idrisrampurawala/exporting-data-to-excel-and-csv-in-angular-3643