vue3 : 导出pdf , 除iframe之外 ,还有其他内容一并导出方式

在 Vue 3 中,如果希望在导出 PDF 时 不仅包含 iframe 内的预览内容,还包含编辑器、按钮等页面其他部分 ,可以使用 html2canvas 捕获整个页面或指定区域,然后通过 jspdf 生成 PDF。以下是优化后的方案:

1. 修改 App.vue(关键部分)

核心思路

  • 捕获整个页面(或指定容器)的 DOM 并转为 Canvas。
  • 调整 PDF 布局(如分页、缩放等)。
  • 处理 iframe 的特殊情况(确保其内容也被正确捕获)。

修改后的代码

xml 复制代码
<template>
  <div class="app" ref="exportContainer"> <!-- 添加 ref,用于捕获整个区域 -->
    <h1>在线代码编辑器 (HTML/CSS/JS)</h1>
    
    <div class="editors">
      <!-- HTML 编辑器 -->
      <div class="editor-container">
        <h3>HTML</h3>
        <Codemirror
          v-model="htmlCode"
          :extensions="[html()]"
          :style="{ height: '300px' }"
        />
      </div>
 
      <!-- CSS 编辑器 -->
      <div class="editor-container">
        <h3>CSS</h3>
        <Codemirror
          v-model="cssCode"
          :extensions="[css()]"
          :style="{ height: '300px' }"
        />
      </div>
 
      <!-- JS 编辑器 -->
      <div class="editor-container">
        <h3>JavaScript</h3>
        <Codemirror
          v-model="jsCode"
          :extensions="[javascript()]"
          :style="{ height: '300px' }"
        />
      </div>
    </div>
 
    <!-- 预览区域 -->
    <div class="preview-container">
      <h2>预览效果</h2>
      <button @click="exportToPDF">导出完整页面为 PDF</button>
      <iframe ref="previewFrame" class="preview-frame"></iframe>
    </div>
  </div>
</template>
 
<script setup>
import { ref, watchEffect } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { html } from '@codemirror/lang-html';
import { css } from '@codemirror/lang-css';
import { javascript } from '@codemirror/lang-javascript';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
 
// 代码状态(同原代码)
const htmlCode = ref(`...`);
const cssCode = ref(`...`);
const jsCode = ref(`...`);
 
// 实时更新预览(同原代码)
const previewFrame = ref(null);
watchEffect(() => {
  if (!previewFrame.value) return;
  const frameDoc = previewFrame.value.contentDocument;
  frameDoc.open();
  frameDoc.write(`
    <!DOCTYPE html>
    <html>
    <head>
      <style>${cssCode.value}</style>
    </head>
    <body>
      ${htmlCode.value}
      <script>${jsCode.value}<\/script>
    </body>
    </html>
  `);
  frameDoc.close();
});
 
// 导出完整页面为 PDF
const exportToPDF = async () => {
  const container = document.querySelector('.app'); // 捕获整个应用区域
  if (!container) return;
 
  // 1. 捕获 DOM 为 Canvas(包括 iframe 内容)
  const canvas = await html2canvas(container, {
    scale: 2, // 提高分辨率
    useCORS: true, // 允许跨域资源
    allowTaint: true, // 允许污染画布(处理 iframe 内容)
    logging: false, // 关闭日志
    windowHeight: container.scrollHeight, // 捕获完整高度
  });
 
  // 2. 计算 PDF 尺寸(A4 尺寸:210mm × 297mm)
  const imgWidth = 190; // 页面宽度(留边距)
  const imgHeight = (canvas.height * imgWidth) / canvas.width; // 按比例缩放高度
 
  // 3. 创建 PDF 并添加图片
  const pdf = new jsPDF('p', 'mm', 'a4');
  let position = 10; // 初始位置(顶部留白)
 
  // 如果内容超过一页,分页处理
  if (imgHeight > 277) { // 297mm - 20mm(边距)
    const pageHeight = 277; // 每页可用高度
    let remainingHeight = imgHeight;
    let offsetY = 0;
 
    while (remainingHeight > 0) {
      const currentHeight = Math.min(pageHeight, remainingHeight);
      const clip = {
        x: 0,
        y: offsetY * (canvas.height / imgHeight), // 按比例计算裁剪位置
        width: canvas.width,
        height: currentHeight * (canvas.height / imgHeight),
      };
 
      // 临时 Canvas 裁剪(需额外处理,此处简化)
      // 实际项目中建议使用 html2canvas 的 `scrollX/scrollY` 或分块渲染
      pdf.addImage(
        canvas.toDataURL('image/png'),
        'PNG',
        10, // 左边距
        position,
        imgWidth,
        currentHeight
      );
 
      remainingHeight -= currentHeight;
      offsetY += currentHeight;
      position += pageHeight; // 移动到下一页
 
      if (remainingHeight > 0) {
        pdf.addPage(); // 添加新页
      }
    }
  } else {
    // 单页直接添加
    pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 10, position, imgWidth, imgHeight);
  }
 
  // 4. 保存 PDF
  pdf.save('full-page-preview.pdf');
};
</script>
 
<style scoped>
/* 原有样式保持不变 */
.app {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  background: white; /* 确保背景为白色(避免透明) */
}
 
/* 其他样式同原代码 */
</style>

2. 关键优化点

(1) 捕获整个页面

  • 通过 ref="exportContainer" 或 document.querySelector('.app') 指定要捕获的区域。
  • html2canvas 默认会捕获所有子元素,包括 iframe(需配置 allowTaint: true)。

(2) 处理 iframe 内容

  • iframe 的内容需要确保可访问(同源或已配置 CORS)。
  • 如果 iframe 是跨域的,可能需要通过 postMessage 通信或使用代理服务器。

(3) 分页处理

  • 单页:直接计算图片尺寸并添加到 PDF。
  • 多页:通过循环计算剩余高度,动态添加新页并调整图片位置。

(4) 分辨率优化

  • 设置 scale: 2 提高 Canvas 分辨率,避免 PDF 模糊。
  • 调整 imgWidth 和 imgHeight 确保内容适配 A4 纸张。

3. 替代方案(更精准的分页)

如果 html2canvas 的分页处理不够精确,可以:

  1. 分块渲染:将页面分成多个部分,分别渲染为 Canvas 后合并到 PDF。

  2. 使用 puppeteer(后端方案) :

    • 通过 Node.js 调用 puppeteer 打印页面为 PDF(支持复杂布局和分页)。
    • 示例代码:
csharp 复制代码
const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('http://localhost:5173', { waitUntil: 'networkidle0' });
  await page.pdf({ path: 'output.pdf', format: 'A4' });
  await browser.close();
})();

4. 最终效果

  • 导出内容 :包含编辑器、按钮、预览区域(iframe 内外全部内容)。
  • 分页支持:自动根据内容高度分页。
  • 高分辨率:PDF 清晰可读。
相关推荐
拆房老料43 分钟前
ONLYOFFICE也能像Microsoft Word和WPS一样分别设置中西文字体
前端·html·word·开源软件·wps
VX_bysjlw9851 小时前
数码设备销售网站设计与实现39138-计算机毕设原创(免费领源码+带部署教程)
java·vue.js·spring boot·mysql·tomcat·mybatis·idea
Solis程序员1 小时前
Stripe 幂等表:把「不确定的重试」变成「查表返回」
前端·安全·bootstrap·php·agent
李纲明1 小时前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生8881 小时前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖2 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34532 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水3 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天3 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
杨杰3984 小时前
我给嵌入式设备写了个 6MB 的 JavaScript 运行时(xuan)
javascript