vue 前端实现导出页面为pdf(分页导出、不分页导出、分模块导出) ...

打印 上一主题 下一主题

主题 901|帖子 901|积分 2703

第一步:下载插件

  1. npm install --save html2canvas       // 页面转图片
  2. npm install jspdf --save             // 图片转pdf
复制代码
第二步:main.js 文件引入

  1. import htmlToPdf from './utils/htmlToPdf';
  2. Vue.use(htmlToPdf);
复制代码
第三步:utils/htmlToPdf.js 文件中界说方法(有三种方法:分页导出、不分页导出、分模块导出;具体方法 见最下边)


第四步:vue页面调用方法 (htmlToPdf)


方法一: 标准打印(分页打印);缺点:分页处会把内容给截断

  1. export default {
  2.   install(Vue) {
  3.     // eslint-disable-next-line func-names
  4.     Vue.prototype.htmlToPdf = function (ele, title) {
  5.       const dom = document.querySelector('#' + ele)
  6.       html2Canvas(dom, {
  7.         useCORS: true,//解决网络图片跨域问题
  8.         width: dom.width,
  9.         height: dom.height,
  10.         windowWidth: dom.scrollWidth,
  11.         dpi: window.devicePixelRatio * 4, // 将分辨率提高到特定的DPI 提高四倍
  12.         scale: 4, // 按比例增加分辨率
  13.       }).then((canvas) => {
  14.         // eslint-disable-next-line new-cap
  15.         const pdf = new JsPDF('p', 'mm', 'a4'); // A4纸,纵向
  16.         const ctx = canvas.getContext('2d');
  17.         const a4w = 170;
  18.         const a4h = 250; // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257
  19.         const imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度
  20.         let renderedHeight = 0;
  21.         while (renderedHeight < canvas.height) {
  22.           const page = document.createElement('canvas');
  23.           page.width = canvas.width;
  24.           page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页
  25.           // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
  26.           page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
  27.           pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 20, 20, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距
  28.           renderedHeight += imgHeight;
  29.           if (renderedHeight < canvas.height) {
  30.             pdf.addPage();// 如果后面还有内容,添加一个空页
  31.           }
  32.           // 预览pdf(这里我用的是事件总线把canvas传递过去展示,达到模拟pdf预览的效果,有用但效果不是很好,有需要的可以自行修改)
  33.           //this.$EventBus.$emit('open-pdf', canvas);
  34.         }
  35.         // 保存文件
  36.         pdf.save(`${title}.pdf`);
  37.       });
  38.     };
  39.   },
  40. }
复制代码
方法二: 标准打印(不分页打印)

  1. export default {
  2.   install(Vue) {
  3.     Vue.prototype.htmlToPdf = function (name, title) {
  4.       html2Canvas(document.querySelector('#' + name), {
  5.         // allowTaint: true,
  6.         useCORS: true,
  7.         scale: 2, // 提升画面质量,但是会增加文件大小
  8.         dpi: window.devicePixelRatio * 1,
  9.       }).then((canvas) => {
  10.         const contentWidth = canvas.width
  11.         const contentHeight = canvas.height
  12.          
  13.          /* 导出不分页处理 */
  14.         const pageData = canvas.toDataURL('image/jpeg', 1.0)
  15.         const pdfWidth = (contentWidth + 10) / 2 * 0.75
  16.         const pdfHeight = (contentHeight + 200) / 2 * 0.75 // 500为底部留白
  17.         const imgWidth = pdfWidth
  18.         const imgHeight = (contentHeight / 2 * 0.75) // 内容图片这里不需要留白的距离
  19.         const PDF = new JsPDF('', 'pt', [ pdfWidth + 50, pdfHeight + 100, ])
  20.         PDF.addImage(pageData, 'jpeg', 33, 33, imgWidth, imgHeight)
  21.         PDF.save(title + '.pdf')
  22.       })
  23.     };
  24.   },
  25. }
复制代码
方法三: 分模块打印(一个模块一个页面)

  1. export default {
  2.   install(Vue) {
  3.     Vue.prototype.htmlToPdf = async function (name, title) {
  4.       const ele = document.querySelector('#' + name)
  5.       const eleW = ele.offsetWidth// 获得该容器的宽
  6.       const eleH = ele.offsetHeight// 获得该容器的高
  7.    
  8.       const eleOffsetTop = ele.offsetTop // 获得该容器到文档顶部的距离
  9.       const eleOffsetLeft = ele.offsetLeft // 获得该容器到文档最左的距离
  10.    
  11.       var canvas = document.createElement('canvas')
  12.       var abs = 0
  13.    
  14.       const win_in = document.documentElement.clientWidth || document.body.clientWidth // 获得当前可视窗口的宽度(不包含滚动条)
  15.       const win_out = window.innerWidth // 获得当前窗口的宽度(包含滚动条)
  16.    
  17.       if (win_out > win_in) {
  18.         // abs = (win_o - win_i)/2;    // 获得滚动条长度的一半
  19.         abs = (win_out - win_in) / 2 // 获得滚动条宽度的一半
  20.         // console.log(a, '新abs');
  21.       }
  22.    
  23.       canvas.width = eleW * 2 // 将画布宽&&高放大两倍
  24.       canvas.height = eleH * 2
  25.    
  26.       var context = canvas.getContext('2d')
  27.    
  28.       context.scale(2, 2)
  29.    
  30.       context.translate(-eleOffsetLeft - abs, -eleOffsetTop)
  31.       // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
  32.       // translate的时候,要把这个差值去掉
  33.    
  34.       var pdf = new JsPDF('', 'pt', 'a4')
  35.       const childrenBox = ele.children
  36.       for (let i = 0; i < childrenBox.length; i++) { // 循环传过来的Dom的字节点 每个子节点打印成一页pdf A4纸那么大
  37.         console.log(childrenBox,'childrenBox');
  38.         console.log(1111);
  39.         const res = await html2Canvas(childrenBox[i], {
  40.           dpi: 300,
  41.           // allowTaint: true,  //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
  42.           useCORS: true, // 允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
  43.           scale: 4, // 提升导出的文件的分辨率
  44.         })
  45.         var pageData = res.toDataURL('image/jpeg', 1.0)
  46.         var contentWidth = res.width
  47.         var contentHeight = res.height
  48.         var imgWidth = 555.28
  49.         var imgHeight = 552.28 / contentWidth * contentHeight
  50.         pdf.addImage(pageData, 'JPEG', 20, 20, imgWidth, imgHeight)
  51.         if (i < childrenBox.length - 1) {
  52.           pdf.addPage() // 避免最后多一个空白页
  53.         }
  54.       }
  55.       pdf.save(`${title}.pdf`);
  56.     };
  57.   },
  58. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

科技颠覆者

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表