Vue + excel下载 + 水印

需要引入两个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中的方法复制一下就行

相关推荐
sure2828 小时前
React Native应用中使用sqlite数据库以及音乐应用中的实际应用
前端·react native
CHU7290358 小时前
扭蛋机盲盒小程序前端功能设计解析:打造趣味与惊喜并存的消费体验
前端·小程序
前端布道师8 小时前
Web响应式:列表自适应布局
前端
ZeroTaboo8 小时前
rmx:给 Windows 换一个能用的删除
前端·后端
哈里谢顿8 小时前
Vue 3 入门完全指南:从零构建你的第一个响应式应用
vue.js
李剑一9 小时前
Vue实现大屏获取当前所处城市及当地天气(纯免费)
前端
_果果然9 小时前
这 7 个免费 Lottie 动画网站,帮你省下一个设计师的工资
前端
QT.qtqtqtqtqt9 小时前
uni-app小程序前端开发笔记(更新中)
前端·笔记·小程序·uni-app
Aliex_git9 小时前
跨域请求笔记
前端·网络·笔记·学习
37方寸9 小时前
前端基础知识(Node.js)
前端·node.js