Vue使用printJS导出网页为pdf、printJS导出pdf

2024-01-09 08:52

本文主要是介绍Vue使用printJS导出网页为pdf、printJS导出pdf,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

先放几个参考链接 感谢!

Vue使用PrintJS实现页面打印功能_vue print.js 设置打印pdf的大小-CSDN博客

前台导出pdf经验汇总 (html2canvas.js和浏览器自带的打印功能-print.js)以及后台一些导出pdf的方法_iqc后台管理系统怎么做到导出pdf-CSDN博客 vue 中使用print.js导出pdf_printjs导出文件命名-CSDN博客

解决使用printJS打印PDF时echarts图表无法打印的问题_print-js打印pdf出现params.printable.charat is not a fu-CSDN博客 printJs库的使用心得 printJs配置 echart table超出_print js 布局设置-CSDN博客

使用printJS打印PDF时cavans、echarts图表无法打印的问题 

当使用浏览器的打印功能window.print()无法打印网页上的canvas图像,但是可以通过转换canvas成一个图片的形式来实现canvas的打印。

解决方法
  • getElementById获取canvas元素。
  • 使用HTMLCanvasElement.toDataURL()的 toDataURL()方法获取canvas的base64码。
  • 将获取的base64动态添加到img标签的src上。(html里的img标签不要写src属性)
<img:src="canvasPrintpdfUrl"style="max-width: 80%; height: auto; display: block; margin: 0 auto"
/>
//canvass 转图片打印var canvass = document.getElementById("myCanvas");var imageURL = canvass.toDataURL("image/png");//获取canvas的base64码//给img的src赋值 _this.canvasPrintpdfUrl = imageURL;

解决使用printJS打印PDF时echarts图表无法打印的问题_print-js打印pdf出现params.printable.charat is not a fu-CSDN博客

截取视频vedio第一帧为图片再导出 ↓ 

js截取video视频某一帧做封面的简单案例_js中截取video作为封面-CSDN博客

需求:网页已经写成了pdf的样式,需要点击导出pdf按钮 调用浏览器系统预览-打印

2.安装

npm install print-js -save

3.引入 在想要引入的页面中添加如下代码

import printJS from 'print-js';

4.使用
在我们想打印内容的标签上添加id,如下

<div id="printContent">
...
...
</div>

简单使用例子

//添加页眉信息并打印图片
printJS({printable: 'images/print-01-highres.jpg', type: 'image', header: 'My cool image header'})//打印多张图片
printJS({printable: ['images/print-01-highres.jpg', 'images/print-02-highres.jpg', 'images/print-03-highres.jpg'],type: 'image', //有四种打印类型:'pdf'、'html'、'image'、'json'。header: 'Multiple Images',imageStyle: 'width:50%;margin-bottom:20px;'
})

配置 建议网上去查

本人项目使用、并适配项目需求仅限参考

问题一:网页需要导出为pdf,并且网页上涉及到 canvas和视频,但是printJs不能直接输出这两个就需要先转化为图片,

问题二:ignoreElements: ["no-print"]的使用 注意class="no-print" 才会生效!

问题三:网页上多图导出的时候 需要循环按比例缩小

  • 直接复制本人修改过的js源码,创建一个Print.js的文件,将下面代码复制进去

getStyle函数中可以写内联样式,覆盖外面原有的样式,以去除一些打印时不需要的而原HTML中有的样式

Print.js、unitChange.js 在最后

vue代码解析

<template>
<div><el-button       type="primary" plain @click="handleprint()">导出PDF</el-button>
<div id="pdfDom"><!-- class="no-print" 就不会打印元素包括该元素下的内容 --><div style="height: 72px" class="no-print">内容</div><div class="page-box">模拟的pdf的第一页</div><div class="page-box">模拟的pdf的第二页 内容包含视频需要转图片<!-- 视频截图需要加 no-print --><div :class="['info_pics_box1','no-print']"><video controls width="250" id="videoplayer"><source src="/media/cc0-videos/flower.webm" type="video/webm"></video></div><!-- 专门用来打印pdf的 用一个图↓ --><img:src="videoPrintUrl"style="max-width: 75%; height: auto; display: block; margin: 0 auto"v-if="videoPrintUrl"/>    </div><div class="page-box">模拟的pdf的第三页<div class="no-print"><canvas id="canvas"></canvas></div><!-- 专门用来打印pdf的 用一个图↓ --><img:src="canvasPrintpdfUrl"style="max-width: 80%; height: auto; display: block; margin: 0 auto"v-if="canvasPrintpdfUrl"/></div>
</div>
</div>
</template>
<script>
import Print from "@/utils/Print.js";
import unitChange from "@/utils/unitChange.js";
export default {
data() {return {pdfUrl: "",videoPrintUrl: "", //视频转图片打印isimgCut: true, //默认是图片截图 视频截图需要加 no-printcanvasPrintpdfUrl: "", //pdf canvas转打印图片}
}methods: {
//导出pdfhandleprint() {let _this = this;const filename = document.title + new Date().getTime();_this.setPrintStyle();_this.$nextTick(() => {Print("#pdfDom", {printable: "pdfDom", // 标签元素idtype: "pdf", // 打印类型// header: "", // '表单名称',targetStyles: ["*"],ignoreElements: ["no-print"], // class="no-print" 就不会打印该元素内容properties: null,documentTitle: filename,//貌似不生效paperSize: {height: "297mm", // 设置打印纸张的高度为 297mm(A4纸)},maxWidth: "100%",font_size: "24px",// 可选-打印时去掉眉页眉尾↓style: `@page{margin:0 10mm;}@media print{html,body{width:1920px;height:100%;margin:0;}}`,afterprint: () => {console.log("打印了");_this.restoredata();//打印后还原页面样式},cancel: () => {console.log("取消打印");_this.restoredata();//打印后还原页面样式},});});},setPrintStyle() {let _this = this;// if (_this.zoomStatus) return;// _this.zoomStatus = true;// 保证打印正好铺满A4高度let A4height = 297; // A4高度297mmlet ctxpage = document.querySelectorAll(".page-box");ctxpage.forEach((i, k) => {let eachpage_mm = unitChange.px2mm(i.clientHeight); // 单位px转mmconsole.log(k + "页高度px:", i.clientHeight, "高度mm:", eachpage_mm);//高度大于A4,则按比例缩小打印区域if (eachpage_mm > A4height) {let zoom = A4height / eachpage_mm;console.log(k + "页zoom:", zoom);i.style.zoom = 1;}});//图片缩小let photos = document.querySelectorAll("#pointers"); //获取页面上的图片id 可以换imgif (photos.length > 0) {photos.forEach((i, k) => {//高度大于A4,则按比例缩小打印区域// i.style.zoom = 0.6;i.style.width = "60%";i.style.display = "block";i.style.margin = "auto";//打印图片居中});}//视频转图片打印_this.$nextTick(() => {let videoplayers = document.querySelector("#videoplayer");if (videoplayers) {var theprintcanvas = document.createElement("canvas"); //创建cavansvar context = theprintcanvas.getContext("2d"); // 获取2D绘图上下文theprintcanvas.width = videoplayers.clientWidth;theprintcanvas.height = videoplayers.clientHeight;// 绘制视频第一帧到画布上context.drawImage(videoplayers, 0, 0);const dataURL = theprintcanvas.toDataURL("image/png");_this.videoPrintUrl = dataURL;} else {console.error("无法找到视频元素或画布元素!");}});//canvass转图片打印let canvass = document.querySelectorAll("canvas");for (var k4 = 0; k4 < canvass.length; k4++) {var imageURL = canvass[k4].toDataURL("image/png");_this.canvasPrintpdfUrl = imageURL;}},//打印后还原页面样式restoredata() {//打印后还原某些元素this.videoPrintUrl = ""; //视频的this.canvasPrintpdfUrl = ""; //pdf canvas转打印图片let ctxpage = document.querySelectorAll(".page-box");ctxpage.forEach((i, k) => {let eachpage_mm = unitChange.px2mm(i.clientHeight); // 单位px转mmi.style.zoom = 1;});let photos = document.querySelectorAll("#pointers");photos.forEach((i, k) => {i.style.width = "100%";});},}
}
</script><style>::-webkit-scrollbar {width: 0 !important;
}
::-webkit-scrollbar {width: 0 !important;height: 0;
}
body::-webkit-scrollbar {display: none;
}
body {-ms-overflow-style: none;
}
html {overflow: -moz-hidden-unscrollable; /*注意!若只打 hidden,chrome 的其它 hidden 会出问题*/height: 100%;
}
/*不打印页脚的链接  --放在样式中*/
@page {margin-top: 1mm;margin-bottom: 1mm;padding-top: 1mm;
}
/*隐藏打印页面不需要的按钮*/
@media print {.btn{display: none;}}
</style>

两个js文件引入:

Print.js

/***** iframe打印* @param dom            打印区域的class, id* @param options.margin  控制页眉页脚, 默认 4mm* @param options.padding 打印边距, 默认 '0 0'* @method options.afterprint 打印结束后回调* @method options.cancel 取消打印后回调** **/const Print = function (dom, options) {if (!(this instanceof Print)) return new Print(dom, options);this.options = this.extend({noPrint: ".no-print",},options);if (typeof dom === "string") {this.dom = document.querySelector(dom);} else {this.isDOM(dom);this.dom = this.isDOM(dom) ? dom : dom.$el;}this.init();
};
Print.prototype = {init: function () {var content = this.getStyle() + this.getHtml();this.writeIframe(content);},extend: function (obj, obj2) {for (var k in obj2) {obj[k] = obj2[k];}return obj;},getStyle: function () {var str = "",styles = document.querySelectorAll("style,link");for (var i = 0; i < styles.length; i++) {str += styles[i].outerHTML;}str +="<style>" +(this.options.noPrint ? this.options.noPrint : ".no-print") +"{display:none;}</style>";str += `<style>@media print { @page { margin: ${this.options.margin || "4mm"}; padding: ${this.options.padding || "0 0"}; width:210mm;height:290mm} body {  -webkit-print-color-adjust:exact;-moz-print-color-adjust:exact;-ms-print-color-adjust:exact;print-color-adjust:exact; } }</style>`;return str;},getHtml: function () {var inputs = document.querySelectorAll("input");var textareas = document.querySelectorAll("textarea");var selects = document.querySelectorAll("select");var canvass = document.querySelectorAll("canvas");var tableNode = document.querySelectorAll(".el-table__header,.el-table__body");for (var k = 0; k < inputs.length; k++) {if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {if (inputs[k].checked == true) {inputs[k].setAttribute("checked", "checked");} else {inputs[k].removeAttribute("checked");}} else if (inputs[k].type == "text") {inputs[k].setAttribute("value", inputs[k].value);} else {inputs[k].setAttribute("value", inputs[k].value);}}for (var k2 = 0; k2 < textareas.length; k2++) {if (textareas[k2].type == "textarea") {textareas[k2].innerHTML = textareas[k2].value;}}for (var k3 = 0; k3 < selects.length; k3++) {if (selects[k3].type == "select-one") {var child = selects[k3].children;for (var i in child) {if (child[i].tagName == "OPTION") {if (child[i].selected == true) {child[i].setAttribute("selected", "selected");} else {child[i].removeAttribute("selected");}}}}}// canvass echars图表转为图片for (var k4 = 0; k4 < canvass.length; k4++) {var imageURL = canvass[k4].toDataURL("image/png");// console.log('imageURL',imageURL)var img = document.createElement("img");img.src = imageURL;img.setAttribute("style", "max-width: 80%;height:auto");img.className = "isNeedRemove";// canvass[k4].style.display = 'none'// canvass[k4].parentNode.style.width = '100%'// canvass[k4].parentNode.style.textAlign = 'center'canvass[k4].parentNode.insertBefore(img, canvass[k4].nextElementSibling);}// console.log(tableNode);//el-table 打印预览的时候,宽度占满// for (let k6 = 0; k6 < tableNode.length; k6++) {//   const tableItem = tableNode[k6];//   tableItem.style.width = "100%";// }return this.dom.outerHTML;},writeIframe: function (content) {var w,doc,iframe = document.createElement("iframe"),f = document.body.appendChild(iframe);iframe.id = "myIframe";iframe.setAttribute("style","position:absolute;width:0;height:0;top:-10px;left:-10px;");w = f.contentWindow || f.contentDocument;doc = f.contentDocument || f.contentWindow.document;doc.open();doc.write(content);doc.close();// 避免重复打印 canvas、echartsvar removes = document.querySelectorAll('.isNeedRemove');for (var k = 0; k < removes.length; k++) {removes[k].parentNode.removeChild(removes[k]);}var _this = this;iframe.onload = function () {w.onbeforeprint = _this.options.beforeprint;w.onafterprint = _this.options.afterprint;// iframe.contentWindow.print();_this.toPrint(w);setTimeout(function () {document.body.removeChild(iframe);}, 100);};},toPrint: function (frameWindow) {var _t = this;try {setTimeout(function () {frameWindow.focus();try {if (!frameWindow.document.execCommand("print", false, null)) {frameWindow.print();}} catch (e) {frameWindow.print();}frameWindow.close();typeof _t.options.cancel === "function" && _t.options.cancel();frameWindow.onbeforeprint = null;frameWindow.onafterprint = null;}, 10);} catch (err) {console.log("err", err);}},isDOM:typeof HTMLElement === "object"? function (obj) {return obj instanceof HTMLElement;}: function (obj) {return (obj &&typeof obj === "object" &&obj.nodeType === 1 &&typeof obj.nodeName === "string");},
};
// 原生JS使用此JS文件实现打印,请删除下边的代码
// const MyPlugin = {};
// MyPlugin.install = function (Vue, options) {
//   // 4. 添加实例方法
//   Vue.prototype.$print = Print;
// };
export default Print;

unitChange.js

//  px <-> mm  单位互相转换/*** 获取DPI 每英寸像素点* @returns {Array}*/
let conversion_getDPI = function() {var DPI = 0;if (window.screen.deviceXDPI) {DPI = window.screen.deviceXDPI;} else {var tmpNode = document.createElement("DIV");tmpNode.style.cssText ="width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";document.body.appendChild(tmpNode);DPI = parseInt(tmpNode.offsetWidth); tmpNode.parentNode.removeChild(tmpNode);} return DPI;};// 1 英寸=25.4 毫米/*** px转换为mm* @param value* @returns {number}*/let px2mm = function(value) {var inch = value / conversion_getDPI();var c_value = inch * 25.4;//      console.log(c_value);return c_value;};/*** mm转换为px* @param value* @returns {number}*/let mm2px = function(value) {var inch = value / 25.4;var c_value = inch * conversion_getDPI();//      console.log(c_value);return c_value;};export default {mm2px,px2mm};

这篇关于Vue使用printJS导出网页为pdf、printJS导出pdf的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/586570

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没