使用printJS使网页打印成PDF、网页html结合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>

配置 建议网上去查

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

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

问题二:ignoreElements: ["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};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/601423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大创项目推荐 深度学习图像分类算法研究与实现 - 卷积神经网络图像分类

文章目录 0 前言1 常用的分类网络介绍1.1 CNN1.2 VGG1.3 GoogleNet 2 图像分类部分代码实现2.1 环境依赖2.2 需要导入的包2.3 参数设置(路径&#xff0c;图像尺寸&#xff0c;数据集分割比例)2.4 从preprocessedFolder读取图片并返回numpy格式(便于在神经网络中训练)2.5 数据预…

ssm基于JSP的网络游戏交易系统的设计与实现+jsp论文

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;商品管理信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足…

面试题理解深层次的数组名

目录 引言 一&#xff1a;一维数组 举例如下 1.铺垫知识 数组名是数组首元素的地址&#xff0c;但是有两个特殊情况 &#xff08;1&#xff09;sizeof(数组名) &#xff08;2&#xff09;&数组名 2.分析讲解上述代码结果 2.字符数组 举例一如下 1.知识铺垫 …

(三)其他的输入输出

文章目录 getchar();单个字符输入使用&#xff1a; putchar();单个字符输出(自带换行)使用 puts();字符串输出与printf区别使用 gets();后面补充 代码现象 getchar(); 单个字符输入 使用&#xff1a; 变量 getchar(); 例&#xff1a;char a&#xff1b; a getchar(); put…

软件测试之单元测试、系统测试、集成测试知识总结

一、单元测试的概念 单元测试是对软件基本组成单元进行的测试&#xff0c;如函数或一个类的方法。当然这里的基本单元不仅仅指的是一个函数或者方法&#xff0c;有可能对应多个程序文件中的一组函数。 单元也具有一些基本的属性。比如&#xff1a;明确的功能、规格定义&#…

PHP进阶-实现网站的QQ授权登录

授权登录是站点开发常见的应用场景&#xff0c;通过社交媒体一键授权可以跳过注册站点账户的繁琐操作。本文将讲解如何用PHP实现QQ授权登录。首先&#xff0c;我们需要申请QQ互联开发者账号获得APPID和密钥&#xff1b;接着&#xff0c;我们下载QQ官方SDK&#xff1a;PHP SDK v…

IP地址定位技术的应用及其重要性

随着网络技术的快速发展&#xff0c;网络安全问题日益凸显&#xff0c;IP地址定位技术在网络安全领域的应用也越来越广泛。本文将介绍IP地址定位技术在网络安全领域的应用及其重要性。 一、IP地址定位技术概述 IP地址定位技术是指通过一定的技术手段&#xff0c;将虚拟网络中的…

关于《码农翻身》一书的读后感以及自己的一些拙见汇总

书籍名称 《码农翻身》 | 刘欣&#xff08;码农翻身&#xff09; 著 | 文章将以问答的形式进行叙述 1.是从什么渠道接触到《码农翻身》的 一个工作日的下午&#xff0c;手上的任务基本结束&#xff0c;翻了翻桌上的书和笔记之类的&#xff0c;同事见我在看书&#xff0c;于是向…

阿里后端实习一面面经

阿里后端实习一面面经 项目中使用到了es&#xff0c;es的作用&#xff1f; elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 es中的重要概念&#xff1f; 群集&#xff1a;一个或多个节点…

PostgreSQL的常见错误和解决方法

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 在学习新的东西时&#xff0c;会犯很多的错误&#xff0c;会遇到很多坑。我们在填坑与犯错中不断进步成长。 以下是在学习pgsql中…

Pytorch详细安装过程

1、安装anaconda 官网&#xff08;https://www.anaconda.com/products/distribution#Downloads&#xff09;下载&#xff0c;使用管理员身份运行&#xff08;不使用似乎也没事&#xff09; 这里选择Just me&#xff08;至于为啥&#xff0c;咱也不是很清楚&#xff09; 更改路…

编程基础 - 初识shell

编程基础 - 初识shell 返回序言及专栏目录 文章目录 编程基础 - 初识shell前言一、Linux的路径1、绝对路径2、相对路径3、特殊路径 二、交互式工作1、先联系上shell2、交互式命令 三、执行脚本四、sh和bash的区别总结 前言 shell是Linux内核外的一层壳&#xff0c;是用户与Li…

大数据 MapReduce如何让数据完成一次旅行?

专栏上一期我们聊到MapReduce编程模型将大数据计算过程切分为Map和Reduce两个阶段&#xff0c;先复习一下&#xff0c;在Map阶段为每个数据块分配一个Map计算任务&#xff0c;然后将所有map输出的Key进行合并&#xff0c;相同的Key及其对应的Value发送给同一个Reduce任务去处理…

数据库设计-DDL

D D L \huge{DDL} DDL DDL&#xff1a;数据库定义语言&#xff0c;用来定义数据对象&#xff08;数据库、表&#xff09; 简单操作 首先在cmd中进行操作&#xff0c;登录数据库 show databases; -- 以列表的形式显示所有的数据库create database [if not exists] 数据库名称…

[C#]使用DlibDotNet人脸检测人脸68特征点识别人脸5特征点识别人脸对齐人脸比对FaceMesh

【官方框架地址】 https://github.com/takuya-takeuchi/DlibDotNet 【算法介绍】 DlibDotNet是一个开源的.NET库&#xff0c;用于实现机器学习和计算机视觉应用。它基于C库dlib&#xff0c;通过C/CLI封装了dlib的所有功能&#xff0c;为.NET开发者提供了简单易用的API。以下是…

Nacos 持久化及集群的搭建【微服务】

文章目录 一、统一配置管理二、微服务配置拉取三、配置热更新四、多环境共享配置五、Nacos 集群搭建1. 集群结构2. 初始化数据库3. 搭建集群 六、Nginx 反向代理七、启动项目测试 一、统一配置管理 案例练习的时候我们只有两个微服务&#xff0c;管理起来非常简单&#xff0c;但…

el-upload上传文件

需求&#xff1a;选中或拖拽文件后&#xff0c;使用http-request属性实现自动上传&#xff0c;并根据后端传回来的结果显示错误和控制fileList的显示&#xff0c;如果后端返回成功&#xff0c;则文件显示在文件列表处&#xff0c;如果后端返回失败&#xff0c;则文件列表不显示…

Qt/QML编程学习之心得:Timer的使用(22)

Qt中timer计时器如何使用? Timer的创建: void InitTimer(){myTimer = new QTimer(q);myTimer->setInterval(100); // 100msmyTimer->setSingleShot(true); //只运行一次的计时器QObject::connect(myTimer,SIGNAL(timeout()),q,SLOT(onTimeOut()));myTimer->start(…

Oracle分区表

文章目录 A. varchar2类型时间字段(20240102)分区实战1. 表要不要分区2. 将已经存在的表改造为分区表(时间字段&#xff0c;varchar2类型)3. 增加分区3.1 增加分区3.2 置换分区&#xff0c;不会复制索引&#xff0c;不要用这种语法建表&#xff0c;这是专门为置换分区用的3.3 分…

SonarQube 漏洞扫描

SonarQube 漏洞扫描 一、部署服务 1.1 docker方式部署 #安装docker curl -L download.beyourself.org.cn/shell-project/os/get-docker-latest.sh | sh yum install -y docker-compose #进去输入:set paste可以保证不穿行 [rootlocalhost sonar]# vim docker-compose.yml v…