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中的方法复制一下就行

相关推荐
anOnion3 小时前
构建无障碍组件之Menu Button pattern
前端·html·交互设计
用户47949283569154 小时前
claude Fable用不了?把Gpt 5.5pro接到你的claude code里
前端·后端
zhangxingchao6 小时前
Kotlin常用的Flow 操作符整理
前端
IT_陈寒8 小时前
React的useState居然还有这种坑?我差点删库跑路
前端·人工智能·后端
Pedantic9 小时前
SwiftUI 手势笔记
前端·后端
橙子家9 小时前
浏览器缓存之【结构化数据库与缓存】: IndexedDB、Cache storage 和 Storage buckets
前端
user20585561518139 小时前
X6 中边悬浮置顶,规避 `mouseleave` 事件丢失问题
前端
李明卫杭州10 小时前
CSS aspect-ratio 属性完全指南
前端
Pedantic11 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端