Vue3 + Vite + TS,使用 ExcelJS导出excel文档,生成水印,添加背景水印,dom转图片,插入图片,全部代码

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);
 });
 }
相关推荐
qiuzen10 个月前
使用nodejs/exceljs读取、操作、写入excel文件
javascript·excel·nodejs·exceljs
念念不忘 必有回响1 年前
exceljs库实现excel表样式定制化
前端·javascript·exceljs