前端将当前页面或者页面中某一部分区域保存成 pdf 文件

前端页面保存成 pdf 文件

需求:前端将页面或者页面中的某一部分导出为 pdf 文件

一、安装依赖

需要使用两个依赖包

html2canvas

将页面转换成图片
html2canvas 的作用就是根据 DOM 生成对应的图片。它的屏幕截图是基于 DOM 的,因此可能不会 100% 精确到真实的表示,因为它不会生成实际的屏幕截图,而是基于页面上可用的信息构建屏幕截图。

npm install html2canvas --save

jspdf

将图片导出成PDF
JSPDF是一个JavaScript库,用于生成PDF文档。它可以直接在浏览器中生成PDF,也可以通过Node.js在服务器端生成PDF。JSPDF具有高度的自定义性和可扩展性,可以用于各种PDF生成需求。

npm install jspdf --save

二、使用 (react项目中使用,其他项目适做修改)

方法声明

注:给需要导出 pdf 的区域挂载 ref
React.createRef();

  import html2canvas from 'html2canvas';
  import jsPDF from 'jspdf';

  this.toPDF_html = React.createRef();
  
  htmlToPdf = () => {
    const element = this.toPDF_html.current; // 需要导出 pdf 文件的 DOM 区域,可以是整个页面也可以是部分区域
    html2canvas(element, {
        useCORS: true, // 允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
        allowTaint: true, // 允许跨域
        scale: 6, // 放大页面倍数,可以调整pdf文件的清晰度
        backgroundColor: '#ffffff'
    }).then((canvas)=> {
        this.canvas2PDF(canvas);
    })
  }
  
  canvas2PDF = canvas => {
    const PDF = new jsPDF({
        orientation: 'p', //参数: l:横向  p:纵向
        unit: 'mm', //参数:测量单位("pt","mm", "cm", "m", "in" or "px")
        format: 'a4', //A4纸
    })
    const ctx = canvas.getContext('2d')
    const a4w = 190
    const a4h = 277 //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
    const imgHeight = Math.floor(a4h * canvas.width / a4w) //按A4显示比例换算一页图像的像素高度
    let renderedHeight = 0

    while (renderedHeight < canvas.height) {
        let page = document.createElement("canvas");
        page.width = canvas.width;
        page.height = Math.min(imgHeight, canvas.height - renderedHeight); //可能内容不足一页

        //用getImageData剪裁指定区域,并画到前面创建的canvas对象中
        page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);

        // canvas转图片数据保留10mm边距
        PDF.addImage(page.toDataURL('image/jpeg', 0.2), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width));

        renderedHeight += imgHeight;

        //判断是否分页,如果后面还有内容,添加一个空页
        if (renderedHeight < canvas.height) {
            PDF.addPage()
        }
    }

    PDF.save("エッコマップ・要約.pdf");
  };
调用方法
<button className="signout-button" onClick={this.htmlToPdf}> 印 刷 </button>
<think>嗯,用户想要一个结合PDF预览、图形绘制、编辑和分页功能的前端实现,用HTML、CSS和JS。首先,我得理清楚每个功能模块的需求。 PDF预览的话,通常可以用PDF.js,因为它是开源的,而且支持在线渲染。可能需要用<canvas>来显示页面。然后分页功能,可能需要上下页按钮,或者显示当前页数,这部分需要动态加载不同的页面。 图形绘制和编辑,可能需要一个画布覆盖在PDF页面上,让用户可以在上面画图。或者用SVG,这样更容易操作元素。但要注意坐标对齐,确保绘制的图形和PDF页面位置对应。事件处理方面,要监听鼠标事件,记录路径或者形状。 分页的话,除了翻页按钮,可能还需要缩略图列表,让用户快速跳转页面。这需要生每个页面的缩略图,可能用PDF.js的渲染功能生小图。 编辑功能包括添加注释、文本框、图形,还有删除和修改。可能需要一个工具栏,选择不同的绘制工具,比如画笔、矩形、箭头等。编辑的话,需要选中已添加的元素,进行拖拽或调整大小,这可能需要事件监听和元素属性的更新。 代码结构方面,先搭建HTML结构,包含预览区域、工具栏、分页控件。CSS要定位元素,比如左侧工具栏,右侧预览区域,底部分页按钮。JS部分处理PDF渲染,用户交互,图形绘制和状态管理。 可能遇到的难点是PDF页面渲染的性能,特别是多页的时候。还有图形元素与PDF页面的坐标同步,比如页面滚动或缩放时,如何保持绘制的内容正确的位置。另外,分页时如何保存当前页的编辑内容,切换到其他页面再回来时恢复状态。 需要用到PDF.js的API,比如加载文档,获取页面,渲染到canvas。图形绘制可能需要一个数组来保存每个页面的元素,切换页面时切换当前操作的数组。事件委托来处理用户交互,比如鼠标按下开始绘制,移动时跟踪,松开结束。 测试时要注意不同PDF文件的兼容性,以及响应式设计,适应不同屏幕尺寸。可能还需要保存功能,将添加的图形数据与PDF关联存储,比如导出为JSON或与后端交互。 总结下来,步骤大概是:初始化PDF渲染,实现分页导航,添加绘图工具和事件处理,管理每页的图形数据,处理页面切换时的状态保存,最后整合UI元素和样式调整。</think>以下是一个结合PDF预览、图形绘制和分页功能的简化版前端实现方案,使用HTML+CSS+JS配合PDF.js库: ```html <!DOCTYPE html> <html> <head> <title>PDF编辑器</title> <style> .container { display: flex; height: 100vh; } #toolbar { width: 200px; background: #f0f0f0; padding: 10px; } #pdf-container { flex: 1; position: relative; overflow: auto; } .page-container { position: relative; margin: 20px auto; box-shadow: 0 0 5px rgba(0,0,0,0.3); } .canvas-container { position: relative; } .annotation-layer { position: absolute; top: 0; left: 0; pointer-events: auto; } .pagination { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); } </style> </head> <body> <div class="container"> <div id="toolbar"> <button onclick="setTool('pen')">画笔</button> <button onclick="setTool('rectangle')">矩形</button> <button onclick="deleteSelected()">删除</button> </div> <div id="pdf-container"> <div id="pdf-viewer"></div> </div> </div> <div class="pagination"> <button id="prev">上一页</button> <span id="page-num">1</span>/<span id="page-count">1</span> <button id="next">下一页</button> </div> <script src="https://mozilla.github.io/pdf.js/build/pdf.js"></script> <script> let pdfDoc = null; let currentPage = 1; let currentTool = 'pen'; let annotations = {}; let isDrawing = false; let startX, startY; // 初始化PDF查看器 pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://mozilla.github.io/pdf.js/build/pdf.worker.js'; // 加载PDF文档 async function loadPDF(url) { const loadingTask = pdfjsLib.getDocument(url); pdfDoc = await loadingTask.promise; renderPage(currentPage); } // 渲染指定页面 async function renderPage(pageNum) { const page = await pdfDoc.getPage(pageNum); const viewport = page.getViewport({ scale: 1.5 }); // 创建canvas容器 const container = document.createElement('div'); container.className = 'page-container'; container.style.width = `${viewport.width}px`; container.style.height = `${viewport.height}px`; // 渲染PDF页面 const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; await page.render({ canvasContext: context, viewport: viewport }).promise; // 创建注释层 const annotationLayer = document.createElement('div'); annotationLayer.className = 'annotation-layer'; annotationLayer.style.width = `${viewport.width}px`; annotationLayer.style.height = `${viewport.height}px`; container.appendChild(canvas); container.appendChild(annotationLayer); document.getElementById('pdf-viewer').appendChild(container); // 添加事件监听 annotationLayer.addEventListener('mousedown', startDrawing); annotationLayer.addEventListener('mousemove', draw); annotationLayer.addEventListener('mouseup', endDrawing); } // 绘图功能 function startDrawing(e) { isDrawing = true; const rect = e.target.getBoundingClientRect(); startX = e.clientX - rect.left; startY = e.clientY - rect.top; } function draw(e) { if (!isDrawing) return; const rect = e.target.getBoundingClientRect(); const currentX = e.clientX - rect.left; const currentY = e.clientY - rect.top; // 根据工具类型绘制图形 switch(currentTool) { case 'pen': drawFreehand(currentX, currentY); break; case 'rectangle': drawRectangle(currentX, currentY); break; } } function endDrawing() { isDrawing = false; } // 工具函数 function setTool(tool) { currentTool = tool; } // 分页控制 document.getElementById('next').addEventListener('click', () => { if(currentPage < pdfDoc.numPages) { currentPage++; renderPage(currentPage); } }); document.getElementById('prev').addEventListener('click', () => { if(currentPage > 1) { currentPage--; renderPage(currentPage); } }); // 初始化加载示例PDF loadPDF('example.pdf'); </script> </body> </html> ``` 核心功能说明: 1. **PDF预览功能**: - 使用PDF.js库实现PDF渲染 - 支持页面缩放和滚动查看 - 动态创建Canvas元素渲染PDF页面 2. **图形绘制功能**: - 支持画笔和矩形绘制 - 独立的注释层用于保存绘制内容 - 鼠标事件处理实现绘图交互 3. **分页功能**: - 上一页/下一页导航 - 显示当前页码和总页数 - 动态加载不同页面内容 4. **编辑功能**: - 工具栏切换不同绘图工具 - 支持删除选定元素(需扩展实现) - 注释数据存储结构(需扩展) 扩展建议: 1. **增强编辑功能**: - 添加更多图形类型(圆形、箭头等) - 实现颜色选择器 - 添加文本输入功能 - 实现撤销/重做功能 2. **状态管理**: - 使用数据结构保存每个页面的注释 - 添加本地存储功能 - 支持导出/导入注释数据 3. **性能优化**: - 实现页面缓存 - 添加加载指示器 - 优化大文档处理 4. **交互增强**: - 支持触屏操作 - 添加缩放功能 - 实现元素选择和拖拽 注意:实际部署时需要处理跨域问题,建议通过服务端代理PDF文件。完整实现需要根据具体需求扩展注释存储、编辑功能和UI交互细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值