当前位置: 首页 > article >正文

react+html2canvas+jspdf将页面导出pdf

主要使用html2canvas+jspdf
1.将前端页面导出为pdf
2.处理导出后图表的截断问题

export default function AIReport() {const handleExport = async () => {try {// 需要导出的内容idconst element = document.querySelector('#AI-REPORT-CONTAINER');if (!element) {message.error('未找到要导出的内容');return;}message.loading({ content: '正在导出PDF...', key: 'export' });// 使用html2canvas生成整个报告的画布const canvas = await html2canvas(element as HTMLElement, {scale: 2, // 提高清晰度useCORS: true,allowTaint: true,backgroundColor: '#ffffff',logging: false,});// 创建PDF对象const pdf = new jsPDF({orientation: 'p', // 纵向unit: 'pt', // 使用点作为单位format: 'a4', // A4纸张});// 获取A4页面尺寸const a4Width = pdf.internal.pageSize.getWidth();const a4Height = pdf.internal.pageSize.getHeight();// 计算等比例下A4高度对应的canvas高度const a4HeightInCanvas = Math.floor((canvas.width / a4Width) * a4Height);// 获取canvas的总高度let leftHeight = canvas.height;// PDF页面偏移量let position = 0;// 创建临时canvas用于分页const tempCanvas = document.createElement('canvas');const ctx = tempCanvas.getContext('2d');// 递归处理每一页const processNextPage = () => {if (leftHeight <= 0) {// 完成所有页面处理,保存并下载PDFconst pdfOutput = pdf.output('blob');const url = URL.createObjectURL(pdfOutput);const link = document.createElement('a');link.href = url;link.download = `AI基金报告_${data?.title || '未命名'}_${data?.date || ''}.pdf`;document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(url);message.success({ content: 'PDF导出成功', key: 'export' });return;}// 计算当前页的高度let currentPageHeight;if (leftHeight > a4HeightInCanvas) {// 需要寻找合适的分页点let cutPoint = position + a4HeightInCanvas;let isFound = false;// 向上搜索连续的空白行作为分页点let checkCount = 0;for (let y = position + a4HeightInCanvas; y >= position; y--) {let isBlankLine = true;// 检查这一行的像素是否全为白色for (let x = 0; x < canvas.width; x += 10) {// 每10个像素采样一次提高性能const pixelData = canvas?.getContext('2d')?.getImageData(x, y, 1, 1).data;// 检查像素是否接近白色(允许一些误差)if (pixelData?.[0] < 250 ||pixelData?.[1] < 250 ||pixelData?.[2] < 250) {isBlankLine = false;break;}}if (isBlankLine) {checkCount++;// 找到连续10行空白,确定为分页点if (checkCount >= 10) {cutPoint = y;isFound = true;break;}} else {checkCount = 0;}}// 如果没找到合适的分页点,就使用默认值currentPageHeight = isFound? Math.round(cutPoint - position): Math.min(leftHeight, a4HeightInCanvas);// 确保高度不为0if (currentPageHeight <= 0) {currentPageHeight = a4HeightInCanvas;}} else {// 最后一页,直接使用剩余高度currentPageHeight = leftHeight;}// 设置临时canvas的尺寸tempCanvas.width = canvas.width;tempCanvas.height = currentPageHeight;// 将原canvas对应部分绘制到临时canvasctx?.drawImage(canvas,0,position,canvas.width,currentPageHeight,0,0,canvas.width,currentPageHeight,);// 从第二页开始添加新页面if (position > 0) {pdf.addPage();}// 将当前页添加到PDFpdf.addImage(tempCanvas.toDataURL('image/jpeg', 1.0),'JPEG',0,0,a4Width,(a4Width / tempCanvas.width) * currentPageHeight,);// 更新剩余高度和位置leftHeight -= currentPageHeight;position += currentPageHeight;// 处理下一页setTimeout(processNextPage, 100);};// 开始处理页面processNextPage();} catch {message.error({ content: '导出PDF失败,请稍后重试', key: 'export' });}};return (<Spin spinning={loading} wrapperClassName={styles.spinWrapper}><div className={styles.exportBtn}><Button type="primary" onClick={handleExport}>导出PDF</Button></div><div className={styles.container} id="AI-REPORT-CONTAINER">这里为需要导出的页面内容,table,echart等</div></Spin>);
}
http://www.lryc.cn/news/2380441.html

相关文章:

  • LWIP的Socket接口
  • 基于支持向量机(SVM)的P300检测分类
  • Better Faster Large Language Models via Multi-token Prediction 原理
  • 51c嵌入式※~合集7~Linux
  • Spring的Validation,这是一套基于注解的权限校验框架
  • MySQL - 如何突破单库性能瓶颈
  • 基于 Vue 和 Node.js 实现图片上传功能:从前端到后端的完整实践
  • go封装将所有数字类型转浮点型,可设置保留几位小数
  • Rust 学习笔记:关于 Vector 的练习题
  • Linux 系统异常触发后自动重启配置指南
  • apisix透传客户端真实IP(real-ip插件)
  • Oracle 数据库的默认隔离级别
  • 统计客户端使用情况,使用es存储数据,实现去重以及计数
  • 代码随想录算法训练营第六十四天| 图论9—卡码网47. 参加科学大会,94. 城市间货物运输 I
  • oracle序列自增问题
  • 开启健康生活的多元养生之道
  • 【Vite】前端开发服务器的配置
  • 鸿蒙OSUniApp 制作自定义弹窗与模态框组件#三方框架 #Uniapp
  • Spring Security与Spring Boot集成原理
  • VScode各文件转化为PDF的方法
  • 精益数据分析(58/126):移情阶段的深度实践与客户访谈方法论
  • Vue3学习(组合式API——Watch侦听器、watchEffect()详解)
  • 【node.js】安装与配置
  • 《AI大模型应知应会100篇》第62篇:TypeChat——类型安全的大模型编程框架
  • HttpMessageConverter 的作用是什么? 它是如何实现请求体到对象、对象到响应体的自动转换的(特别是 JSON/XML)?
  • EdgeShard:通过协作边缘计算实现高效的 LLM 推理
  • 火山 RTC 引擎9 ----集成 appkey
  • ArcGIS Pro 3.4 二次开发 - 框架
  • Adminer:一个基于Web的轻量级数据库管理工具
  • RK3568下QT实现按钮切换tabWidget