Vue3 + Vite + TS,使用 ExcelJS导出excel文档,生成水印,添加背景水印,dom转图片,插入图片,全部代码
ExcelJS
读取,操作并写入电子表格数据和样式到 XLSX 和 JSON 文件。
一个 Excel 电子表格文件逆向工程项目。
exceljs 中文API 传送门
生成文档并导出
js
import * as ExcelJS from "exceljs";
// 创建文档对象
const workbook = new ExcelJS.Workbook();
// 创建工作本
const worksheet = workbook.addWorksheet('Sheet 1');
// 冻结表头
worksheet.views = [{
state: 'frozen', // 可以设置为 'frozen' 来固定首行或首列,模拟滚动条效果
xSplit: 0, // 从第二列开始冻结(模拟滚动条效果)
ySplit: 9, // 从第二行开始冻结(模拟滚动条效果)
topLeftCell: 'A1' // 设置起始位置为 B2,模拟滚动效果从第二行第二列开始
}];
// 1. 构建表头结构
const headerDepth = buildHeaders(filterColumns,7);
// 递归生成表头行
generateHeaderRows(worksheet,headerDepth,filterColumns,7);
// 2. 填充数据
// salesTable.value.tableData.forEach(item => {
// worksheet.addRows(item);
// })
// 触发下载
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = name+'.xlsx';
link.click();
导出表头其他函数
js
// 递归生成表头行
export const generateHeaderRows = (worksheet:Worksheet,headerDepth:number,cols:tableColumn[], currentRow = 0, startCol = 0) => {
cols.forEach(col => {
const cell = {
header: col.label,
key: col.dataIndex,
width: col.minWidth?parseInt(col.minWidth)/8 : 20,
colSpan: col.childrens ? col.childrens.length : 1,
rowSpan: col.childrens ? 1 : headerDepth - currentRow + 1
};
const tempCell = worksheet.getCell(currentRow + 1, startCol + 1);
// 设置单元格文案
tempCell.value = col.label;
// 设置单元格字体与大小
tempCell.font = { name: 'Arial', size: 10 }
// 设置列宽度
worksheet.getColumn(startCol+1).width = cell.width;
// 设置行高
worksheet.getRow(currentRow+1).height = 20;
// 合并单元格
worksheet.mergeCells(
currentRow + 1,
startCol + 1,
currentRow + (cell.rowSpan || currentRow+1),
startCol + (cell.colSpan || 1)
);
// 有子级递归
if (col.childrens) {
generateHeaderRows(worksheet,headerDepth,col.childrens, currentRow + 1, startCol);
}
startCol += cell.colSpan;
});
}
// 递归处理表头层级
export const buildHeaders = (columns:tableColumn[], depth = 0, parentSpan = 0) => {
let maxDepth = depth;
columns.forEach((col:tableColumn) => {
if (col.childrens) {
const childDepth = buildHeaders(col.childrens, depth + 1, parentSpan + (col.colSpan|| 0));
maxDepth = Math.max(maxDepth, childDepth);
}
});
return maxDepth;
};
生成水印
js
export const createWatermark = () => {
// 创建 Canvas 元素并绘制水印
const canvas = document.createElement('canvas');
const context:CanvasRenderingContext2D | null = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 200;
context?context.font = '14px Arial':'';
// 旋转角度
context?context.rotate(-25 * Math.PI / 180):'';
// 设置文本内容的当前对齐方式
context?context.textAlign = 'center':'';
context?context.fillStyle = 'rgba(0, 0, 0, 0.1)':''; // 半透明水印
context?context.fillText('midea', canvas.width / 2 - 100, canvas.height / 2):'';
// 将 Canvas 转换为图片数据 URL
return canvas.toDataURL('image/png');
}
设置文档的背景水印
js
// 将 Canvas 水印 转换为图片数据 URL
const imageDataUrl = createWatermark();
// 添加图片到工作簿中
const imageId = workbook.addImage({
base64: imageDataUrl.replace(/^data:image\/[a-z]+;base64,/, ''),
extension: 'png',
});
// 设置文档水印
worksheet.addBackgroundImage(imageId)
dom 转图片
js
import domToImage from 'dom-to-image';
// 把查询条件转为图片
domToImage.toPng(captureRef.value).then(async (dataUrl) => {
const image = new Image();
image.src = dataUrl;
})
.catch(function (error) {
console.error('Failed to generate image:', error);
});
插入图片
js
const imageId2 = workbook.addImage({ base64: dataUrl, extension: 'png' });
// 工作本插入查询条件图片
worksheet.addImage(imageId2, {
tl: { col: 0, row: 0 },
ext: { width: 1900 / 1.3, height: 800 / 6 }
});
全部代码
js
// 递归生成表头行
export const generateHeaderRows = (worksheet:Worksheet,headerDepth:number,cols:tableColumn[], currentRow = 0, startCol = 0) => {
cols.forEach(col => {
const cell = {
header: col.label,
key: col.dataIndex,
width: col.minWidth?parseInt(col.minWidth)/8 : 20,
colSpan: col.childrens ? col.childrens.length : 1,
rowSpan: col.childrens ? 1 : headerDepth - currentRow + 1
};
const tempCell = worksheet.getCell(currentRow + 1, startCol + 1);
// 设置单元格文案
tempCell.value = col.label;
// 设置单元格字体与大小
tempCell.font = { name: 'Arial', size: 10 }
// 设置列宽度
worksheet.getColumn(startCol+1).width = cell.width;
// 设置行高
worksheet.getRow(currentRow+1).height = 20;
// 合并单元格
worksheet.mergeCells(
currentRow + 1,
startCol + 1,
currentRow + (cell.rowSpan || currentRow+1),
startCol + (cell.colSpan || 1)
);
// 有子级递归
if (col.childrens) {
generateHeaderRows(worksheet,headerDepth,col.childrens, currentRow + 1, startCol);
}
startCol += cell.colSpan;
});
}
// 递归处理表头层级
export const buildHeaders = (columns:tableColumn[], depth = 0, parentSpan = 0) => {
let maxDepth = depth;
columns.forEach((col:tableColumn) => {
if (col.childrens) {
const childDepth = buildHeaders(col.childrens, depth + 1, parentSpan + (col.colSpan|| 0));
maxDepth = Math.max(maxDepth, childDepth);
}
});
return maxDepth;
};
export const createWatermark = () => {
// 创建 Canvas 元素并绘制水印
const canvas = document.createElement('canvas');
const context:CanvasRenderingContext2D | null = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 200;
context?context.font = '14px Arial':'';
// 旋转角度
context?context.rotate(-25 * Math.PI / 180):'';
// 设置文本内容的当前对齐方式
context?context.textAlign = 'center':'';
context?context.fillStyle = 'rgba(0, 0, 0, 0.1)':''; // 半透明水印
context?context.fillText('midea', canvas.width / 2 - 100, canvas.height / 2):'';
// 将 Canvas 转换为图片数据 URL
return canvas.toDataURL('image/png');
}
// 点击下载
const downLoadList = () => {
// 创建文档对象
const workbook = new ExcelJS.Workbook();
// 创建工作本
const worksheet = workbook.addWorksheet('Sheet 1');
// 冻结表头
worksheet.views = [{
state: 'frozen', // 可以设置为 'frozen' 来固定首行或首列,模拟滚动条效果
xSplit: 0, // 从第二列开始冻结(模拟滚动条效果)
ySplit: 9, // 从第二行开始冻结(模拟滚动条效果)
topLeftCell: 'A1' // 设置起始位置为 B2,模拟滚动效果从第二行第二列开始
}];
// 1. 构建表头结构
const headerDepth = buildHeaders(filterColumns,7);
// 递归生成表头行
generateHeaderRows(worksheet,headerDepth,filterColumns,7);
emit('downLoadList',workbook,worksheet);
}
const downLoadListFn = async (workbook:Workbook,worksheet:Worksheet,name:string) => {
// 把查询条件转为图片
domToImage.toPng(captureRef.value).then(async (dataUrl) => {
const image = new Image();
image.src = dataUrl;
const imageId2 = workbook.addImage({ base64: dataUrl, extension: 'png' });
// 工作本插入查询条件图片
worksheet.addImage(imageId2, {
tl: { col: 0, row: 0 },
ext: { width: 1900 / 1.3, height: 800 / 6 }
});
// 2. 填充数据
// salesTable.value.tableData.forEach(item => {
// worksheet.addRows(item);
// })
// 将 Canvas 水印 转换为图片数据 URL
const imageDataUrl = createWatermark();
// 添加图片到工作簿中
const imageId = workbook.addImage({
base64: imageDataUrl.replace(/^data:image\/[a-z]+;base64,/, ''),
extension: 'png',
});
// 设置文档水印
worksheet.addBackgroundImage(imageId)
// 触发下载
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = name+'.xlsx';
link.click();
})
.catch(function (error) {
console.error('Failed to generate image:', error);
});
}