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

相关文章

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

prometheus如何使用pushgateway监控网路丢包

《prometheus如何使用pushgateway监控网路丢包》:本文主要介绍prometheus如何使用pushgateway监控网路丢包问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录监控网路丢包脚本数据图表总结监控网路丢包脚本[root@gtcq-gt-monitor-prome

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

SpringBoot线程池配置使用示例详解

《SpringBoot线程池配置使用示例详解》SpringBoot集成@Async注解,支持线程池参数配置(核心数、队列容量、拒绝策略等)及生命周期管理,结合监控与任务装饰器,提升异步处理效率与系统... 目录一、核心特性二、添加依赖三、参数详解四、配置线程池五、应用实践代码说明拒绝策略(Rejected

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window