需要引入两个js库
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'
<template>
<div class="excel-watermark-component">
<button
@click="exportExcelWithWatermark"
class="download-btn"
:disabled="isExporting"
>
<i class="fas fa-file-excel"></i>
{{ isExporting ? '正在生成...' : '下载带水印Excel' }}
</button>
</div>
</template>
<script>
import ExcelJS from 'exceljs'
import { saveAs } from 'file-saver'
export default {
name: 'ExcelWatermark',
data() {
return {
isExporting: false,
watermarkText: 'CONFIDENTIAL',
filename: '带水印Excel文件',
sampleData: [
{
'姓名': '张三',
'部门': '技术部',
'工资': '15000',
'奖金': '5000'
},
{
'姓名': '李四',
'部门': '市场部',
'工资': '12000',
'奖金': '3000'
},
{
'姓名': '王五',
'部门': '财务部',
'工资': '13000',
'奖金': '4000'
}
]
}
},
methods: {
// 生成重复平铺的水印图片
generateTiledWatermarkImage(text) {
const tileSize = 400 // 单个水印图块尺寸
const canvas = document.createElement('canvas')
canvas.width = tileSize
canvas.height = tileSize
const ctx = canvas.getContext('2d')
// 设置透明背景
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 保存当前状态
ctx.save()
// 移动到中心点并旋转
ctx.translate(tileSize / 2, tileSize / 2)
ctx.rotate(-30 * Math.PI / 180) // 30度转换为弧度
// 设置文字样式
ctx.font = 'bold 30px Arial'
ctx.fillStyle = 'rgba(128, 128, 128, 0.1)' // 浅灰色半透明
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
// 在中心绘制水印文字
ctx.fillText(text, 0, 0)
ctx.restore()
return canvas.toDataURL('image/png').split(',')[1] // 返回base64数据部分
},
// 导出带水印的Excel文件
async exportExcelWithWatermark() {
if (this.isExporting) return
try {
this.isExporting = true
// 创建工作簿
const workbook = new ExcelJS.Workbook()
workbook.created = new Date()
workbook.modified = new Date()
// 创建工作表
const worksheet = workbook.addWorksheet('数据表')
// 添加示例数据
const headers = Object.keys(this.sampleData[0])
const headerRow = worksheet.addRow(headers)
// 设置表头样式
headerRow.eachCell((cell, colNumber) => {
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE8E8E8' }
}
cell.font = {
bold: true,
size: 12
}
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
}
})
// 添加数据行
this.sampleData.forEach(item => {
const rowData = headers.map(header => item[header])
console.log(rowData);
worksheet.addRow(rowData)
})
// 生成水印图片并设置为背景
const base64Watermark = this.generateTiledWatermarkImage(this.watermarkText)
const imageId = workbook.addImage({
base64: base64Watermark,
extension: 'png'
})
// 设置水印为重复平铺背景
worksheet.addBackgroundImage(imageId)
// 设置列宽
worksheet.columns = headers.map(() => ({ width: 15 }))
// 生成Excel文件并下载
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
saveAs(blob, `${this.filename}.xlsx`)
this.$message.success('Excel文件导出成功!')
} catch (error) {
console.error('导出Excel文件时出错:', error)
this.$message.error('导出失败:' + error.message)
} finally {
this.isExporting = false
}
}
}
}
</script>
<style scoped>
.excel-watermark-component {
display: inline-block;
}
.download-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.download-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}
.download-btn:disabled {
background: #a0aec0;
cursor: not-allowed;
}
.download-btn i {
margin-right: 8px;
}
</style>
如果是vue3 直接把methods中的方法复制一下就行