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

相关推荐
用户904706683577 分钟前
Nuxt css 如何写?
前端
神秘的猪头7 分钟前
🎨 CSS 这种“烂大街”的技术,怎么在 React 和 Vue 里玩出花来?—— 模块化 CSS 深度避坑指南
css·vue.js·react.js
夏天想8 分钟前
element-plus的输入数字组件el-input-number 显示了 加减按钮(+ -) 和 小三角箭头(上下箭头),怎么去掉+,-或者箭头
前端·javascript·vue.js
0思必得09 分钟前
[Web自动化] Selenium基础介绍
前端·python·selenium·自动化·web自动化
Filotimo_11 分钟前
前端.d.ts文件作用
前端
进击的野人11 分钟前
Vue 3 响应式数据解构:toRef 与 toRefs 的深度解析
前端·vue.js·前端框架
ohyeah12 分钟前
CSS 作用域隔离实战:React、Vue 与 Styled Components 的三种范式
前端
徐赛俊18 分钟前
Excel 打开后界面一片灰、无工作表的原因与解决方案(Markdown 教程)
excel
二哈喇子!28 分钟前
前端HTML、CSS、JS、VUE 汇总
开发语言·前端
小白路过29 分钟前
node-sass和sass兼容性使用
前端·rust·sass