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 模糊。
  • 调整 imgWidthimgHeight 确保内容适配 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 清晰可读。
相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax