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 清晰可读。
相关推荐
好好研究1 小时前
使用JavaScript实现轮播图的自动切换和左右箭头切换效果
开发语言·前端·javascript·css·html
paopaokaka_luck3 小时前
基于Spring Boot+Vue的吉他社团系统设计和实现(协同过滤算法)
java·vue.js·spring boot·后端·spring
伍哥的传说5 小时前
Radash.js 现代化JavaScript实用工具库详解 – 轻量级Lodash替代方案
开发语言·javascript·ecmascript·tree-shaking·radash.js·debounce·throttle
程序视点5 小时前
IObit Uninstaller Pro专业卸载,免激活版本,卸载清理注册表,彻底告别软件残留
前端·windows·后端
前端程序媛-Tian5 小时前
【dropdown组件填坑指南】—怎么实现下拉框的位置计算
前端·javascript·vue
iamlujingtao6 小时前
js多边形算法:获取多边形中心点,且必定在多边形内部
javascript·算法
嘉琪0016 小时前
实现视频实时马赛克
linux·前端·javascript
烛阴6 小时前
Smoothstep
前端·webgl
若梦plus6 小时前
Eslint中微内核&插件化思想的应用
前端·eslint
爱分享的程序员6 小时前
前端面试专栏-前沿技术:30.跨端开发技术(React Native、Flutter)
前端·javascript·面试