第一步:下载插件
| npm install --save html2canvas |
| npm install jspdf --save |
复制
第二步:main.js 文件引入
| import htmlToPdf from './utils/htmlToPdf'; |
| Vue.use(htmlToPdf); |
复制
第三步:utils/htmlToPdf.js 文件中定义方法(有三种方法:分页导出、不分页导出、分模块导出;具体方法 见最下边)

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

方法一: 标准打印(分页打印);缺点:分页处会把内容给截断
| export default { |
| install(Vue) { |
| // eslint-disable-next-line func-names |
| Vue.prototype.htmlToPdf = function (ele, title) { |
| const dom = document.querySelector('#' + ele) |
| html2Canvas(dom, { |
| useCORS: true,//解决网络图片跨域问题 |
| width: dom.width, |
| height: dom.height, |
| windowWidth: dom.scrollWidth, |
| dpi: window.devicePixelRatio * 4, // 将分辨率提高到特定的DPI 提高四倍 |
| scale: 4, // 按比例增加分辨率 |
| }).then((canvas) => { |
| // eslint-disable-next-line new-cap |
| const pdf = new JsPDF('p', 'mm', 'a4'); // A4纸,纵向 |
| const ctx = canvas.getContext('2d'); |
| const a4w = 170; |
| const a4h = 250; // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257 |
| const imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度 |
| let renderedHeight = 0; |
| |
| while (renderedHeight < canvas.height) { |
| const 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); |
| pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 20, 20, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距 |
| |
| renderedHeight += imgHeight; |
| if (renderedHeight < canvas.height) { |
| pdf.addPage();// 如果后面还有内容,添加一个空页 |
| } |
| // 预览pdf(这里我用的是事件总线把canvas传递过去展示,达到模拟pdf预览的效果,有用但效果不是很好,有需要的可以自行修改) |
| //this.$EventBus.$emit('open-pdf', canvas); |
| } |
| // 保存文件 |
| pdf.save(`${title}.pdf`); |
| }); |
| }; |
| }, |
| } |
复制
方法二: 标准打印(不分页打印)
| export default { |
| install(Vue) { |
| Vue.prototype.htmlToPdf = function (name, title) { |
| html2Canvas(document.querySelector('#' + name), { |
| // allowTaint: true, |
| useCORS: true, |
| scale: 2, // 提升画面质量,但是会增加文件大小 |
| dpi: window.devicePixelRatio * 1, |
| }).then((canvas) => { |
| const contentWidth = canvas.width |
| const contentHeight = canvas.height |
| |
| /* 导出不分页处理 */ |
| const pageData = canvas.toDataURL('image/jpeg', 1.0) |
| |
| const pdfWidth = (contentWidth + 10) / 2 * 0.75 |
| const pdfHeight = (contentHeight + 200) / 2 * 0.75 // 500为底部留白 |
| |
| const imgWidth = pdfWidth |
| const imgHeight = (contentHeight / 2 * 0.75) // 内容图片这里不需要留白的距离 |
| |
| const PDF = new JsPDF('', 'pt', [ pdfWidth + 50, pdfHeight + 100, ]) |
| PDF.addImage(pageData, 'jpeg', 33, 33, imgWidth, imgHeight) |
| PDF.save(title + '.pdf') |
| }) |
| }; |
| }, |
| } |
复制
方法三: 分模块打印(一个模块一个页面)
| export default { |
| install(Vue) { |
| Vue.prototype.htmlToPdf = async function (name, title) { |
| const ele = document.querySelector('#' + name) |
| const eleW = ele.offsetWidth// 获得该容器的宽 |
| const eleH = ele.offsetHeight// 获得该容器的高 |
| |
| const eleOffsetTop = ele.offsetTop // 获得该容器到文档顶部的距离 |
| const eleOffsetLeft = ele.offsetLeft // 获得该容器到文档最左的距离 |
| |
| var canvas = document.createElement('canvas') |
| var abs = 0 |
| |
| const win_in = document.documentElement.clientWidth || document.body.clientWidth // 获得当前可视窗口的宽度(不包含滚动条) |
| const win_out = window.innerWidth // 获得当前窗口的宽度(包含滚动条) |
| |
| if (win_out > win_in) { |
| // abs = (win_o - win_i)/2; // 获得滚动条长度的一半 |
| abs = (win_out - win_in) / 2 // 获得滚动条宽度的一半 |
| // console.log(a, '新abs'); |
| } |
| |
| canvas.width = eleW * 2 // 将画布宽&&高放大两倍 |
| canvas.height = eleH * 2 |
| |
| var context = canvas.getContext('2d') |
| |
| context.scale(2, 2) |
| |
| context.translate(-eleOffsetLeft - abs, -eleOffsetTop) |
| // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此 |
| // translate的时候,要把这个差值去掉 |
| |
| var pdf = new JsPDF('', 'pt', 'a4') |
| const childrenBox = ele.children |
| for (let i = 0; i < childrenBox.length; i++) { // 循环传过来的Dom的字节点 每个子节点打印成一页pdf A4纸那么大 |
| console.log(childrenBox,'childrenBox'); |
| console.log(1111); |
| const res = await html2Canvas(childrenBox[i], { |
| dpi: 300, |
| // allowTaint: true, //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的 |
| useCORS: true, // 允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。 |
| scale: 4, // 提升导出的文件的分辨率 |
| }) |
| var pageData = res.toDataURL('image/jpeg', 1.0) |
| var contentWidth = res.width |
| var contentHeight = res.height |
| var imgWidth = 555.28 |
| var imgHeight = 552.28 / contentWidth * contentHeight |
| pdf.addImage(pageData, 'JPEG', 20, 20, imgWidth, imgHeight) |
| if (i < childrenBox.length - 1) { |
| pdf.addPage() // 避免最后多一个空白页 |
| } |
| } |
| |
| pdf.save(`${title}.pdf`); |
| }; |
| }, |
| } |
复制