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

相关推荐
起个名字逛街玩2 小时前
前端正在走向“工程系统化”:从页面开发到复杂产品架构的深度进化
前端·架构
用户47949283569152 小时前
React 渲染两次:是 Bug 还是 Feature?聊聊严格模式的“良苦用心”
前端·react.js·前端框架
b***74883 小时前
前端GraphQL案例
前端·后端·graphql
云飞云共享云桌面3 小时前
无需配置传统电脑——智能装备工厂10个SolidWorks共享一台工作站
运维·服务器·前端·网络·算法·电脑
ganshenml3 小时前
sed 流编辑器在前端部署中的作用
前端·编辑器
0***K8924 小时前
Vue数据挖掘开发
前端·javascript·vue.js
t***26594 小时前
SpringBoot + vue 管理系统
vue.js·spring boot·后端
蓝胖子的多啦A梦4 小时前
ElementUI表格错位修复技巧
前端·css·vue.js·el-table表格错位
_OP_CHEN4 小时前
前端开发实战深度解析:(一)认识前端和 HTML 与开发环境的搭建
前端·vscode·html·web开发·前端开发