Vue项目中将界面转换为PDF并导出的实现方案

1. 主要技术栈

项目使用了以下库来实现PDF导出功能:

  • html2canvas:将HTML元素转换为canvas图像
  • jspdf:生成PDF文件
  • 自定义的打印插件:基于vue-print-nb改进,支持水印等功能
javascript 复制代码
npm install html2canvas jspdf

2. 核心实现方式

使用html2canvas + jspdf直接生成PDF

javascript 复制代码
// 生成PDF的核心方法
async generatePDF() {
  try {
    // 获取要导出的DOM元素
    const element = this.$refs.pdfContent;
    
    // 临时隐藏不需要打印的元素
    const noPrintElements = element.querySelectorAll('.no-print');
    const originalDisplays = [];
    noPrintElements.forEach((el, index) => {
      originalDisplays[index] = el.style.display;
      el.style.display = 'none';
    });

    // 临时添加PDF导出专用样式
    const style = document.createElement('style');
    style.id = 'pdf-export-style';
    style.textContent = `
      .duty-table {
        width: 1200px !important;
        max-width: none !important;
        font-size: 14px !important;
        // ... 更多样式
      }
    `;
    document.head.appendChild(style);

    // 创建canvas
    const canvas = await html2canvas(element, {
      scale: 2, // 清晰度
      useCORS: true,
      allowTaint: true,
      backgroundColor: '#ffffff',
      width: 1200,
      height: element.scrollHeight,
      ignoreElements: (el) => {
        return el.classList.contains('no-print');
      }
    });

    // 恢复隐藏的元素和样式
    noPrintElements.forEach((el, index) => {
      el.style.display = originalDisplays[index];
    });
    document.getElementById('pdf-export-style')?.remove();

    // 创建PDF
    const imgData = canvas.toDataURL('image/png', 1.0);
    const pdf = new jsPDF('p', 'mm', 'a4');
    
    // 计算图片在PDF中的尺寸并添加到PDF
    const a4Width = 210;
    const a4Height = 297;
    const margin = 5;
    // ... 尺寸计算逻辑
    pdf.addImage(imgData, 'PNG', xOffset, yOffset, imgWidth, imgHeight);

    // 转换为Blob对象
    const pdfBlob = pdf.output('blob');
    const fileName = `排班表_${this.currentDate}_${new Date().getTime()}.pdf`;
    
    return {
      fileName: fileName,
      pdfBlob: pdfBlob,
      message: "PDF生成成功"
    };
  } catch (error) {
    console.error('PDF导出错误:', error);
    return null;
  }
}

3. 实现要点总结

样式处理

  1. 为不需要打印的元素添加no-print类
  2. 临时添加专为PDF导出优化的CSS样式
  3. 处理字体和颜色(打印时通常需要将背景色设为白色)

导出流程

  1. 获取需要导出的DOM元素
  2. 使用html2canvas将其渲染为canvas
  3. 使用jspdf将canvas图像转换为PDF
  4. 通过Blob对象处理PDF数据,提供下载或上传功能

特殊处理

  1. 水印添加:通过CSS或在canvas上叠加实现
  2. 分页处理:计算内容高度,必要时分页
  3. 样式隔离:临时添加导出专用样式,处理完成后恢复

4. 使用示例

javascript 复制代码
// 直接下载PDF
async exportPDF() {
  const result = await this.generatePDF();
  if (result) {
    const url = URL.createObjectURL(result.pdfBlob);
    const link = document.createElement('a');
    link.href = url;
    link.download = result.fileName;
    link.click();
    URL.revokeObjectURL(url);
  }
}

// 上传PDF到服务器
async exportAndUpload() {
  const result = await this.generatePDF();
  if (result && result.pdfBlob) {
    const formData = new FormData();
    const pdfFile = new File([result.pdfBlob], result.fileName, {
      type: "application/pdf",
    });
    formData.append("pdfFile", pdfFile);
    // 发送请求上传文件
    await uploadPDF(formData);
  }
}
相关推荐
90后的晨仔4 小时前
Vue 3 组合式函数(Composables)全面解析:从原理到实战
前端·vue.js
今天头发还在吗4 小时前
【React】TimePicker进阶:解决开始时间可大于结束时间的业务场景与禁止自动排版
javascript·react.js·ant design
今天头发还在吗4 小时前
【React】动态SVG连接线实现:图片与按钮的可视化映射
前端·javascript·react.js·typescript·前端框架
小刘不知道叫啥4 小时前
React 源码揭秘 | suspense 和 unwind流程
前端·javascript·react.js
90后的晨仔5 小时前
Vue 3 中 Provide / Inject 在异步时不起作用原因分析(二)?
前端·vue.js
90后的晨仔5 小时前
Vue 3 中 Provide / Inject 在异步时不起作用原因分析(一)?
前端·vue.js
90后的晨仔5 小时前
Vue 异步组件(defineAsyncComponent)全指南:写给新手的小白实战笔记
前端·vue.js
木易 士心5 小时前
Vue 与 React 深度对比:底层原理、开发体验与实际性能
前端·javascript·vue.js
Lucky GGBond6 小时前
Vue + Spring Boot 实现 Excel 导出实例
vue.js·spring boot·excel