Nuxt 3中如何用无漏洞包将Vue组件导出为PDF?
Vue复杂嵌套组件导出PDF解决方案
问题背景
在risk.vue页面中引入了RiskGrid.vue组件,该组件包含300+硬编码网格项、大量自定义样式,且嵌套RiskGridTable.vue子组件。需要通过按钮触发导出功能,将该组件完整导出为包含标题、描述和网格内容的PDF文件。此前尝试html2pdf、vue-html2pdf、jspdf等工具,要么存在已知漏洞,要么导出效果不符合预期。
代码结构示例
risk.vue
<TabPanel value="0" class="tab-panel"> <div ref="rizikSazetakRef"> <RiskGrid v-if="vrstaIzracuna == 'Djelatnost'" :tip="'RZ'" class="rizik-sazetak" /> <span v-else> <font-awesome-icon icon="info-circle" style="margin-right: 5px;" /> Nije odabrana vrsta izračuna </span> </div> </TabPanel> <button class="action-icon" @click="downloadRizikSazetak"> <font-awesome-icon icon="download" size="lg" /> </button> <script setup> const downloadRizikSazetak = () => { // 待实现导出逻辑 }; </script>
RiskGrid.vue(片段)
<template> <div class="rizik-sazetak"> <div v-if="showPopup" class="success-popup"> <font-awesome-icon :icon="'circle-exclamation'" /> <span>{{ message }}</span> <div class="progress-bar" /> </div> <div class="sazetak"> <div ref="rizikSazetakRef" class="grid-table"> <!-- 300+网格项代码 --> <div class="grid-item vertical lightgreen db-l">Wind changes</div> <div class="grid-item table-header">First-al</div> <div class="grid-item table-header">First-bl</div> <div class="grid-item table-header">First-cl</div> <div class="grid-item table-header">First-dl</div> <div class="grid-item table-item nb-b"> <RiskGridTable :pozicija="12" :data="structuredData['12']" class="sazetak-table" /> </div> <!-- 更多网格项代码 --> </div> <LegendaBoja v-if="structuredData" class="legenda" /> </div> </div> </template> <style scoped> /* 大量自定义样式 */ .vertical { writing-mode: sideways-lr; text-orientation: upright; text-align: center; text-wrap: wrap; font-size: 14px; padding: 5px; border-right: none; border-left: none; border-bottom: none; } .grid-item:nth-child(57) { grid-row: 7; grid-column: 12; } .grid-item:nth-child(58) { grid-row-start: 4; grid-column-start: 13; grid-row-end: 8; grid-column-end: 20; } .grid-item:nth-child(59) { grid-column: 20; grid-row: 4 / 8; } /* 更多样式代码 */ </style>
RiskGridTable.vue(片段)
<template> <div> <div v-if="data" class="grid"> <div class="_grid-item first-div" :class="getColorClass(data[0].history)"> <span class="first" :style="getFontSize(data[0].history)"> {{ data[0].history }} </span> </div> <div class="_grid-item db-s" :class="getColorClass(data[0].p0_4_5)" :style="getFontSize(data[0].p0_4_5)"> {{ data[0].p0_4_5 }} </div> <div class="_grid-item" :class="getColorClass(data[0].p0_8_5)" :style="getFontSize(data[0].p0_8_5)"> {{ data[0].p0_8_5 }} </div> <!-- 更多子网格项代码 --> </div> </div> </template>
解决方案:html2canvas + jsPDF组合方案
选择无已知高危漏洞的稳定版本,手动组合实现导出,可控性更强。
步骤1:安装依赖
npm install html2canvas@1.4.1 jspdf@2.5.1
步骤2:实现导出函数
修改risk.vue的<script setup>部分:
<script setup> import { ref } from 'vue'; import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; const rizikSazetakRef = ref(null); const downloadRizikSazetak = async () => { if (!rizikSazetakRef.value) return; // 克隆目标元素,避免干扰原页面渲染 const cloneElement = rizikSazetakRef.value.cloneNode(true); document.body.appendChild(cloneElement); try { // 生成Canvas,提高分辨率避免PDF模糊 const canvas = await html2canvas(cloneElement, { scale: 2, useCORS: true, logging: false, }); // 初始化PDF,设置A4尺寸 const pdf = new jsPDF('p', 'mm', 'a4'); const imgWidth = 210; const pageHeight = 297; const imgHeight = (canvas.height * imgWidth) / canvas.width; let position = 30; // 预留标题、描述空间 // 添加自定义标题和描述 pdf.setFontSize(16); pdf.text('风险网格报告', 10, 15); pdf.setFontSize(12); pdf.text('报告描述内容', 10, 25); // 添加网格内容到PDF pdf.addImage(canvas, 'PNG', 0, position, imgWidth, imgHeight); let remainingHeight = imgHeight - (pageHeight - position); // 处理分页逻辑 while (remainingHeight > 0) { position = remainingHeight - imgHeight; pdf.addPage(); pdf.addImage(canvas, 'PNG', 0, position, imgWidth, imgHeight); remainingHeight -= pageHeight; } // 下载PDF文件 pdf.save('风险网格报告.pdf'); } catch (error) { console.error('PDF导出失败:', error); } finally { // 清理克隆的临时元素 document.body.removeChild(cloneElement); } }; </script>
关键注意事项
- 样式兼容性:Vue的scoped样式会自动添加元素属性选择器,克隆元素时会保留该属性,因此样式可正常渲染。若仍有样式丢失,可将组件核心样式移至全局样式文件。
- 分辨率优化:设置
scale:2可提升Canvas分辨率,避免导出的PDF模糊。 - 分页处理:代码中自动处理超长内容的分页,确保所有网格项都能完整导出。
- 漏洞规避:指定安装无已知高危漏洞的版本,避免使用老旧依赖包。
内容的提问来源于stack exchange,提问作者Antonio Klepo
相关产品推荐
相关产品推荐

