1、安装依赖
//如果是导出单个文件
npm install excelJs
npm install file-saver
//以压缩包形式导出
npm install excelJs
npm install jszip
npm install file-saver
2、实现
安装好相关依赖后,需要去设置文件的样式。
docFiles.js
//这里的data为每个文件的数据
/**
* 设置配置项
* @param {Array[Object]} data.list 表格数据
* @param {String} sheetName sheet名称
*/
export const fundRelease = (data) => {
let config = [];
const header1 = [`${data.countyName}${data.townName}${data.villageName}农户参加农业生产托管财政补贴资金确认发放表`];
let header2 = [
`接受服务方(盖章):${data.villageGroup} 村级组织负责人签字:${data.villageGroupLeader} 服务组织签字(盖章):`,
];
let header3 = ['序号', '姓名'];
let oncItem = {
//表格数据
data: data.list,
//表格每一列数据对应属性名
fields: [
"number",
"name",
],
headers: [header1, header2, header3],
merges: [],
attrs: [],
view: [],
//设置每列的宽度
columnsWidth: [10, 10],
//sheet名
sheetName: data.sheetName,
};
// 设置全表单元格边框,居中布局
oncItem.attrs.push({
rowStart: 0,
rowEnd: data.farmers.length + 4,//这部分根据实际数据调整
colStart: 0,
colEnd: oncItem.fields.length - 1,
attr: {
alignment: { vertical: "middle", horizontal: "center", wrapText: true },
border: {
top: { style: "thin" },
left: { style: "thin" },
bottom: { style: "thin" },
right: { style: "thin" },
},
},
});
// 设置表头填充颜色,字体加粗
oncItem.attrs.push({
rowStart: 0,
rowEnd: 0,
colStart: 0,
colEnd: oncItem.fields.length - 1,
attr: {
fill: {
type: "pattern",
pattern: "solid",
// fgColor: { argb: "99CCFF" }
fgColor: {},
},
font: {
bold: true,
},
},
});
// row:行, col:列, rowspan: 合并的行数 , colspan: 合并的列数
let tableItem = [
//合并单元格
{
row: 0,
col: 0,
rowspan: 1,
colspan: 2,
},
];
oncItem.merges = tableItem;
config.push(oncItem);
return config;
};
这里定义了一个方法fundRelease ,接收到文件数据data后,对表格的行和列进行内容设置、合并等操作。表格需要的配置选项有以下几种:
| 配置项 | 配置项 | 配置项 |
|---|---|---|
| headers | [string] | 有几个表头就设置几个header,header以数组的形式展示,每一个元素代表一个单元格。 |
| data | [object] | 列表数据,循环部分。 |
| fields | [string] | 每一列数据对应属性名。 |
| columnsWidth | [number] | 每列的宽度。 |
| sheetName | string | sheet名 |
| attrs | [object] | 表单样式设置。 |
文件的配置样式设置好之后,我们就可以去创建Excel文件了。
◇ 单个文件
这里我们先从创建单个文件开始,首先定义一个方法 createExcelByData用于创建excel文件,文件创建完之后通过saveAs()保存到本地。
// 封装exceljs
import ExcelJS from 'exceljs'
import FileSaver from 'file-saver'
/**
* 导出数据到Excel方法
* @param {Array[Object]} config.data 表格数据
* @param {Array[String]} config.fields 字段列表
* @param {Array[String]} config.headers excel表头列表[[]],可以是多级表头[['A1','B1'],['A2','B2']]
* @param {Array[Object]} config.merges 需要合并的单元格,需要考虑表头的行数[{row:1, col:1, rowspan: 1, colspan: 2}]
* @param {Array[Object]} config.attrs 单元格样式配置
* @param {Array[Object]} config.views 工作表视图配置
* @param {Array[Number]} columnsWidth 每个字段列对应的宽度
* @param {Object} config.protect 工作表保护【此配置会保护全表,一般推荐只针对单元格进行保护配置】
* @param {String} sheetName 工作表名称,默认从sheet1开始
* @param {String} fileName excel文件名称
*/
export function exportDataToExcel(config, fileName) {
if (!config) return;
const options = {
fileName: fileName || `导出excel文件【${Date.now()}】.xlsx`,
worksheets: []
}
if (!Array.isArray(config)) {
config = [config]
}
config.forEach((item) => {
// 深拷贝data【JSON.stringify有缺陷,可自行换成_.cloneDeep】
const data = JSON.parse(JSON.stringify(item.data));
const results = data.map(obj => {
return item.fields.map(key => {
return obj[key]
})
})
// 生成完整excel数据
let excelData = [];
excelData = excelData.concat(item.headers).concat(results);
// 单元格合并处理【excel数据的第一行/列是从1开始】
let excelMerges = [];
excelMerges = item.merges.map(m => {
return [m.row + 1, m.col + 1, m.row + m.rowspan, m.col + m.colspan]
})
// 单元格配置处理【excel数据的第一行/列是从1开始】
let excelAttrs = [];
excelAttrs = item.attrs.map(attr => {
attr.rowStart += 1;
attr.rowEnd += 1;
attr.colStart += 1;
attr.colEnd += 1;
return attr
})
options.worksheets.push({
data: excelData,
merges: excelMerges,
attrs: excelAttrs,
views: item.views,
columnsWidth: item.columnsWidth,
protect: item.protect,
sheetName: item.sheetName
})
})
createExcel(options)
}
// 创建Excel文件方法
async function createExcel(options) {
if (!options.worksheets.length) return;
// 创建工作簿
const workbook = new ExcelJS.Workbook();
for (let i = 0; i < options.worksheets.length; i++) {
const sheetOption = options.worksheets[i];
// 创建工作表
const sheet = workbook.addWorksheet(sheetOption.sheetName || 'sheet' + (i + 1));
// 添加数据行
sheet.addRows(sheetOption.data);
// 配置视图
sheet.views = sheetOption.views;
// 单元格合并处理【开始行,开始列,结束行,结束列】
if (sheetOption.merges) {
sheetOption.merges.forEach((item) => {
sheet.mergeCells(item);
});
}
// 工作表保护
if (sheetOption.protect) {
const res = await sheet.protect(sheetOption.protect.password, sheetOption.protect.options);
}
// 单元格样式处理
if (sheetOption.attrs.length) {
sheetOption.attrs.forEach((item) => {
const attr = item.attr || {};
// 获取开始行-结束行; 开始列-结束列
const rowStart = item.rowStart;
const rowEnd = item.rowEnd;
const colStart = item.colStart;
const colEnd = item.colEnd;
if (rowStart) { // 设置行
for (let r = rowStart; r <= rowEnd; r++) {
// 获取当前行
const row = sheet.getRow(r);
if (colStart) { // 列设置
for (let c = colStart; c <= colEnd; c++) {
// 获取当前单元格
const cell = row.getCell(c);
Object.keys(attr).forEach((key) => {
// 给当前单元格设置定义的样式
cell[key] = attr[key];
});
}
} else {
// 未设置列,整行设置【大纲级别】
Object.keys(attr).forEach((key) => {
row[key] = attr[key];
});
}
}
} else if (colStart) { // 未设置行,只设置了列
for (let c = colStart; c <= colEnd; c++) {
// 获取当前列,整列设置【大纲级别】
const column = sheet.getColumn(c);
Object.keys(attr).forEach((key) => {
column[key] = attr[key];
});
}
} else {
// 没有设置具体的行列,则为整表设置
Object.keys(attr).forEach((key) => {
sheet[key] = attr[key];
});
}
})
}
// 列宽设置
if (sheetOption.columnsWidth) {
for (let i = 0; i < sheet.columns.length; i++) {
sheet.columns[i].width = sheetOption.columnsWidth[i]
}
}
}
// 生成excel文件
workbook.xlsx.writeBuffer().then(buffer => {
// application/octet-stream 二进制数据
FileSaver.saveAs(new Blob([buffer], { type: 'application/octet-stream' }), options.fileName)
})
}
◇ 批量导出
import ExcelJS from 'exceljs'
import FileSaver from 'file-saver'
import JsZip from 'jszip'
//引入设置表格配置方法
import { fundRelease } from "@/utils/excel/fundRelease";
/**
* 异步函数:批量下载包含多个文件夹的ZIP文件
* 此函数用于将多个文件夹中的内容打包成一个ZIP文件,并下载到本地
* 主要用途是当需要将一批文件(如报表)整理到一个文件夹中,并以ZIP格式下载时
*
* @param {Array} folderList - 包含待处理文件夹信息的数组每个文件夹可能包含多个文件
* @param {string} zipName - 打包后ZIP文件的名称,也是顶层文件夹的名称
* @param {string} excelType - 文件类型,主要用于处理Excel文件
*/
export async function downloadFilesZipWithFolder(folderList, zipName) {
const zip = new JsZip();
// 在ZIP中创建第一个文件夹
const firstFolder = zip.folder(zipName);
// 批量处理文件夹
const exportPromise = folderList.map(async (item) => await handleFolder(firstFolder, item));
await Promise.all(exportPromise);
// 生成并下载 zip 文件
zip.generateAsync({ type: "blob" }).then((blob) => {
saveAs(blob, `${zipName}.zip`);
});
}
/**
* 生成文件夹
* @param {*} preFolder 上一级目录的folder数据
* @param {*} file 当前文件夹相关数据
*/
async function handleFolder(preFolder, file) {
let nextFolder = preFolder.folder(file.name);
let catalogue= file?.catalogue? file.catalogue: [];//文件夹一层数据
let files = file?.sheets? file.sheets: [];//文件一层数据
let folderPromises = []
let promises = []
if (catalogue.length) {
folderPromises = catalogue.map(async (child) => {
await handleFolder(nextFolder, child); // 递归处理子文件夹
});
}
if (files.length) {
promises = files.map(async (file) => {
await handleEachFile(nextFolder, file); // 递归处理子文件夹
});
}
await Promise.all([...promises, ...folderPromises]);
}
/**
* 异步处理每个文件
* 并将处理结果合并后导出为单个Excel文件
* @param {string} preFolder - 前置文件夹路径,用于指定Excel文件的保存位置
* @param {Object} file- 村庄对象,包含村庄名称和村庄小组信息
* @param {boolean} excelType - Excel类型标志,决定处理村庄小组的方式
*/
async function handleEachFile(preFolder, file) {
let tableArr = [];
let excelPromise = [];
for (let index = 0; index < file.group.length; index++) {
let sheet= file.sheets[index];
tableArr = tableArr.concat(fundRelease(sheet));
}
if (tableArr.length > 0) {
await exportSingleExcel(tableArr, {
fileName: `${file.name}`, rowHeightAble: true, rowHeight: 30
}, preFolder);
}
tableArr = [];
}
/**
* 导出单个Excel文件
* @param {Object|Object[]} config - Excel配置对象或配置对象数组
* @param {Object} opts - 选项对象
* @param {Object} preFolder - 用于保存文件的前置文件夹对象
*/
async function exportSingleExcel(config, opts, preFolder) {
let {
fileName,//文件名称
rowHeightAble,//是否自定义行高度
rowHeight,//行高度,rowHeightAble为true时生效
} = Object.assign({
fileName: `导出excel文件【${Date.now()}】.xlsx`,
rowHeightAble: false,
}, opts || {})
if (!config) return;
const options = {
fileName,
worksheets: [],
rowHeightAble,
rowHeight,
}
if (!Array.isArray(config)) {
config = [config]
}
for (let index = 0; index < config.length; index++) {
const item = config[index];
// 深拷贝data【JSON.stringify有缺陷,可自行换成_.cloneDeep】
const data = JSON.parse(JSON.stringify(item.data));
const results = data.map(obj => {
return item.fields.map(key => {
return obj[key]
})
})
// 生成完整excel数据
let excelData = [];
excelData = excelData.concat(item.headers).concat(results);
// 单元格合并处理【excel数据的第一行/列是从1开始】
let excelMerges = [];
excelMerges = item.merges.map(m => {
return [m.row + 1, m.col + 1, m.row + m.rowspan, m.col + m.colspan]
})
// 单元格配置处理【excel数据的第一行/列是从1开始】
let excelAttrs = [];
excelAttrs = item.attrs.map(attr => {
attr.rowStart += 1;
attr.rowEnd += 1;
attr.colStart += 1;
attr.colEnd += 1;
return attr
})
options.worksheets.push({
data: excelData,
merges: excelMerges,
attrs: excelAttrs,
views: item.views,
columnsWidth: item.columnsWidth,
protect: item.protect,
sheetName: item.sheetName
})
}
// 等待 writeBuffer 解析完成
const writeBuffer = await createExcel(options);
// 创建 blob 并添加到文件夹
const blob = new Blob([writeBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
// 使用 preFolder 对象的方法将文件保存
preFolder.file(`${fileName}.xlsx`, blob);
}
/**
* 异步函数,用于创建Excel文件
* @param {Object} options - 包含工作表信息的选项对象
* @returns {Promise<Buffer>} 返回生成的Excel文件的Buffer对象
*/
async function createExcel(options) {
if (!options.worksheets.length) return;
// 创建工作簿
const workbook = new ExcelJS.Workbook();
for (let i = 0; i < options.worksheets.length; i++) {
const sheetOption = options.worksheets[i];
// 创建工作表
const sheet = workbook.addWorksheet(sheetOption.sheetName || 'sheet' + (i + 1));
// 添加数据行
sheet.addRows(sheetOption.data);
// 配置视图
sheet.views = sheetOption.views;
// 单元格合并处理【开始行,开始列,结束行,结束列】
if (sheetOption.merges) {
sheetOption.merges.forEach((item) => {
sheet.mergeCells(item);
});
}
// 工作表保护
if (sheetOption.protect) {
const res = await sheet.protect(sheetOption.protect.password, sheetOption.protect.options);
}
// 单元格样式处理
if (sheetOption.attrs.length) {
sheetOption.attrs.forEach((item) => {
const attr = item.attr || {};
// 获取开始行-结束行; 开始列-结束列
const rowStart = item.rowStart;
const rowEnd = item.rowEnd;
const colStart = item.colStart;
const colEnd = item.colEnd;
if (rowStart) { // 设置行
for (let r = rowStart; r <= rowEnd; r++) {
// 获取当前行
const row = sheet.getRow(r);
if (colStart) { // 列设置
for (let c = colStart; c <= colEnd; c++) {
// 获取当前单元格
const cell = row.getCell(c);
Object.keys(attr).forEach((key) => {
// 给当前单元格设置定义的样式
cell[key] = attr[key];
});
}
} else {
// 未设置列,整行设置【大纲级别】
Object.keys(attr).forEach((key) => {
row[key] = attr[key];
});
}
}
} else if (colStart) { // 未设置行,只设置了列
for (let c = colStart; c <= colEnd; c++) {
// 获取当前列,整列设置【大纲级别】
const column = sheet.getColumn(c);
Object.keys(attr).forEach((key) => {
column[key] = attr[key];
});
}
} else {
// 没有设置具体的行列,则为整表设置
Object.keys(attr).forEach((key) => {
sheet[key] = attr[key];
});
}
})
}
// 列宽设置
if (sheetOption.columnsWidth) {
for (let i = 0; i < sheet.columns.length; i++) {
sheet.columns[i].width = sheetOption.columnsWidth[i]
}
}
// 行高设置
if (options.rowHeightAble) {
sheet.eachRow({ includeEmpty: true }, function (row, rowNumber) {
row.height = options.rowHeight;
});
}
}
// 生成excel文件
let writeBuffer = await workbook.xlsx.writeBuffer()
return await workbook.xlsx.writeBuffer();
}
应用页面
注释部分为批量导出代码
import { exportDataToExcel } from "@/utils/exportDataToExcel";
import { downloadFilesZipWithFolder} from '@/constants/excelsDownload.js'
import { fundRelease } from '@/utils/farmers'
/**导出的数据*/
let excelData={
name:'sheet1',
list:[]
}
/*let excelDataList=[
{
name:'目录1',
catalogue:[
{
name:'目录1-1',
catalogue:[
{
name:'文件4',
sheets:[
{
name:'sheet1',
list:[]
}
]
}
]
},
]
},
{
name:'目录2',
catalogue:[
{
name:'文件2',
sheets:[
{
name:'sheet1',
list:[]
}
]
},
{
name:'文件3',
sheets:[
{
name:'sheet1',
list:[]
}
]
},
]
},
{
name:'文件1',
sheets:[
{
name:'sheet1',
list:[]
}
]
}
]*/
/**导出数据事件*/
function exportData(){
let sheetName='sheet1'
let tableArr = [];
tableArr = tableArr.concat(fundRelease (excelData.value));
let tableName = '信息表';
exportDataToExcel(tableArr, `${tableName}.xlsx`);
tableArr = [];
//downloadFilesZipWithFolder(excelDataList, '确认表')
}
以上就是导出文件的全部内容了。