本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、组件开发目的
- 重写
Element
的el-button
组件,实现在点击按钮的同时,将需要导出的数据导出到Excel文件中。
二、组件开发依赖
exceljs
:^4.3.0
file-saver
:^2.0.5
三、组件代码
<!-- 该组件重写了el-button组件,支持el-button所有用法 -->
<!-- 1、增加了导出excel的功能:父组件通过传递book参数,将表格数据传递给本组件,由本组件负责导出为excel -->
<template>
<button
class="el-button"
@click="handleClick"
:disabled="buttonDisabled || loading"
:autofocus="autofocus"
:type="nativeType"
:class="[
type ? 'el-button--' + type : '',
buttonSize ? 'el-button--' + buttonSize : '',
{
'is-disabled': buttonDisabled,
'is-loading': loading,
'is-plain': plain,
'is-round': round,
'is-circle': circle
}
]"
>
<i class="el-icon-loading" v-if="loading"></i>
<i :class="icon" v-if="icon && !loading"></i>
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
<script>
import resolveResponse from '@/util/response';
import ExcelJS from 'exceljs';
import FileSaver from 'file-saver';
export default {
name: 'ExportToExcelButton',
inject: {
elForm: {
default: '',
},
elFormItem: {
default: '',
},
},
props: {
type: {
type: String,
default: 'default',
},
size: String,
icon: {
type: String,
default: '',
},
nativeType: {
type: String,
default: 'button',
},
loading: Boolean,
disabled: Boolean,
plain: Boolean,
autofocus: Boolean,
round: Boolean,
circle: Boolean,
book: {
type: Object,
default() {
return {
fileName: '',
sheets: [
{
sheetName: '',
sheetData: [[], [], []],
},
],
};
},
},
},
computed: {
// eslint-disable-next-line no-underscore-dangle
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
buttonSize() {
// eslint-disable-next-line no-underscore-dangle
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
},
buttonDisabled() {
return this.disabled || (this.elForm || {}).disabled;
},
},
data() {
return {
loadingFlag: false,
workbook: {},
};
},
methods: {
// el-button原生方法
handleClick(evt) {
this.$emit('click', evt); // 将click事件传给父组件
this.exportToExcel(); // 导出excel
},
// excel导出相关方法
async exportToExcel() {
// 1.创建工作簿
await this.createWorkBook();
// 2.创建工作表
const promise = [];
await this.book.sheets.forEach((sheet) => {
promise.push(this.createWorkSheet(sheet.sheetName, sheet.sheetData));
});
await Promise.all(promise);
// 3.下载excel表格
await this.downloadExcel();
},
createWorkBook() {
this.workbook = new ExcelJS.Workbook();
this.workbook.created = new Date();
this.workbook.modified = new Date();
this.workbook.lastPrinted = new Date();
},
async createWorkSheet(sheetName, sheetData) {
const workSheet = this.workbook.addWorksheet(sheetName);
workSheet.addRows(sheetData);
},
downloadExcel() {
this.workbook.xlsx.writeBuffer()
.then((buffer) => {
FileSaver.saveAs(new Blob([buffer]), `${this.book.fileName}_${Date.now()}.xlsx`);
})
.catch((err) => {
this.$message.error(`excel导出失败,原因为:${err}`);
});
},
},
};
</script>
四、组件使用方法
- 在vue项目里导入
exceljs
和file-saver
相关依赖。 - 新建一个名为
ExportToExcelButton
的vue文件,把第三部分的代码复制进去。 - 在父组件里注册
ExportToExcelButton
组件,并把需要导出的数据通过ExportToExcelButton
组件的book
参数传给ExportToExcelButton
组件。 - 由于是重写的
el-buton
组件,所以ExportToExcelButton
组件支持el-button
组件的所有方法,且不需要element-ui
依赖。el-button
组件的用法可以参考:官方文档 - 使用Demo:
<template>
<export-to-excel-button
type="primary"
:book="book"
>
Demo
</export-to-excel-button>
</template>
<script>
import ExportToExcelButton from '@/components/button/ExportToExcelButton.vue';
export default {
name: 'Demo',
components: { ExportToExcelButton },
data() {
return {
book: {
fileName: 'Demo',
sheets: [
{
sheetName: 'sheet1',
sheetData: [
['A1'],
['A2', 'B2'],
['A3', 'B3', 'C3'],
],
},
{
sheetName: 'sheet2',
sheetData: [
['A1', 'B1', 'C1'],
['A2', 'B2'],
['A3'],
],
},
],
},
};
},
};
</script>
<style scoped>
</style>
五、不足之处
- 目前组件还不支持富文本和图片,有兴趣的可以根据ExcelJS官网教程,自行封装。