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};

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

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

相关文章

使用fs.renameSync(oldPath,newPath)方法,报错Error: EPERM: operation not permitted

出错翻译&#xff1a;表示操作被拒绝&#xff0c;因为当前用户没有足够的权限执行该操作。这可能是由于文件或目录 的权限设置不正确或操作系统限制所致 出现错误场景&#xff1a;使用element-plus的Upload 上传功能&#xff1b;后端使用Nodejs提供的fs.renameSync(oldPath,ne…

可碧教你C++——位图

本章节是哈希的延申 可碧教你C——哈希http://t.csdnimg.cn/3R8TU 一文详解C——哈希 位图 位图是基于哈希表的原理产生的一种新的container——bitset 基于哈希映射的原理&#xff0c;我们在查找的时候&#xff0c;可以直接去定址到元素的具体位置&#xff0c;然后直接访问该…

OpenAI ChatGPT-4开发笔记2024-04:Chat之Tool之2:multiple functions

从程序员到ai Expert 1 定义参数和函数2 第一轮chatgpt3 第一轮结果和function定义全部加入prompt再喂给chatgpt4 大结局7 参考资料 上一篇解决了调用一个函数的问题。这一篇扩展为调用3个。n个自行脑补。 1 定义参数和函数 #1.设定目标 import json import openai#1.定义para…

基于JavaWeb+BS架构+SpringBoot+Vue协同推荐的黔醉酒业白酒销售系统的设计和实现

基于JavaWebBS架构SpringBootVue基于协同推荐的黔醉酒业白酒销售系统系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 1.2 国内外研究概况 2 1.3 研究的内容 2 1.4 本章…

mybatisPlus 将List<String>字段转成json字符串,使用JacksonTypeHandler以及自定义类型处理器实现

文章目录 场景使用JacksonTypeHandler实现类型转换自定义StringListTypeHandler处理器实现 场景 项目中经常需要将List转成json存储到配置文件中, mybatisPlus默认实现了JacksonTypeHandler&#xff0c;GsonTypeHandler&#xff0c;FastjsonTypeHandler&#xff0c;也可以自定义…

JAVA基础语句1

目录 前言 一.JAVA特性 简单 面向对象 分布式 多线程 二.关键字 三.对象和类 对象 类 构造方法 创建对象 访问实例变量和方法 源文件声明规则 Java 包 import 语句 总结 前言 这里参考了&#xff1a;Java 教程 | 菜鸟教程 (runoob.com) 第一个必须是&#xff1a; hello world&a…

Github 2024-01-09Python开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-09统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目10Jupyter Notebook项目1 Payloads All The Things - 有用的Web应用程序安全负载和绕过列表 创建…

带前后端H5即时通讯聊天系统源码

带有前后端的H5即时通讯聊天系统源码。该源码是一个开源的即时通信demo&#xff0c;需要前后端配合使用。它的主要目的是为了促进学习和交流&#xff0c;并为大家提供开发即时通讯功能的思路。尽管该源码提供了许多功能&#xff0c;但仍需要进行自行开发。该项目最初的开发初衷…

C#.Net学习笔记——CLR核心机制

一、CLR基本介绍 &#xff08;1&#xff09;C(Common) L&#xff08;Language&#xff09; R&#xff08;Runtime&#xff09; IL的运行环境 &#xff08;2&#xff09;从下图可以看到&#xff0c;我们的计算机会先把我们写的语言&#xff0c;编写成IL语言&#xff0c;再给计…

Gartner发布2024年SASE融合战略路线图

向云计算和远程工作的转变增加了 SASE 需求&#xff0c;以实现从任何设备的安全访问。安全和风险管理领导者必须将网络和安全融合到一两个明确合作的 SASE 供应商产品中&#xff0c;并淘汰遗留的边界系统。 主要发现 安全访问服务边缘 (SASE) 框架为混合劳动力以及设备、分支机…

java基础之HashMap练习题

应用了 外循环&#xff0c;自循环&#xff0c;Lambda表达式&#xff0c;keySet&#xff08;&#xff09;方法&#xff0c;values&#xff08;&#xff09;方法&#xff0c;Entry对象 &#xff0c;entrySet&#xff08;&#xff09;方法 Map集合框架 1:(Map)关于下列Map 接口中…

AI问答系统与对话机器人服务(一)

知识要点 微软认知服务中知识库服务的申请与搭建 如何用REST API访问知识库数据 微软认知服务中机器人服务的申请与搭建 如何无缝集成知识库服务与机器人服务 建立知识库 什么叫QnA Maker? 知识库&#xff0c;就是人们总结出的一些历史知识的集合&#xff0c;存储、索引…

Windows 双网卡链路聚合解决方案

Windows 双网卡链路聚合解决方案 链路聚合方案1&#xff1a;Metric介绍操作 方案2&#xff1a;NetSwitchTeam介绍操作 方案3&#xff1a;NIC介绍操作 方案4&#xff1a;Intel PROSet 链路聚合 指将多个物理端口汇聚在一起&#xff0c;形成一个逻辑端口&#xff0c;以实现出/入…

办公文档,私人专用

一、安装Minio 1.1、创建文件夹&#xff0c;并在指定文件夹中下载minio文件 cd /opt mkdir minio cd minio touch minio.log wget https://dl.minio.io/server/minio/release/linux-amd64/minio1.2、赋予minio文件执行权限 chmod 777 minio1.3、启动minio ./minio server /…

Python3+Selenium+Chrome实现自动填写WPS表单

引言 本文通过python3、第三方python库Selenium和谷歌浏览器Chrome&#xff0c;完成WPS表单的自动填写。 开发环境配置 python3的安装&#xff1a;略&#xff0c;网上都有教程。 Selenium的安装&#xff1a;在命令行输入pip3 install selenium并回车即可完成安装&#xff0c;如…

(Matlab)基于CNN-Bi_LSTM的多维时序回归预测(卷积神经网络-双向长短期记忆网络)

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码展示&#xff1a; 四、完整代码数据下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平…

局域网IP地址冲突、环路的罪魁祸首是什么?

中午好&#xff0c;我的网工朋友。 这个时代&#xff0c;网络已经贯穿了人们的生活&#xff0c;对企业而言&#xff0c;办公信息化更是离不开网络支持。 为了提高安全管理和信息化水平&#xff0c;很多企业都建立了完善的办公信息系统&#xff0c;但一些企业在网络建设方面还…

适合培训协会搭建的培训机构管理系统开发方案

一、项目背景与目标 &#xff08;一&#xff09;项目背景 培训学校教务管理系统是培训机构数字化管理的必备系统&#xff0c;该系统功能大大提升机构办学的管理效率、提升机构在家长心中的专业度&#xff0c;市面上的培训机构管理系统收费越来越贵&#xff0c;为了给协会内培…

高功率电源PCB设计中变压器底层走线的关键要点

高功率电源的设计中&#xff0c;变压器起到了电能的传递与转换的重要作用。变压器下方的走线设计不仅涉及到电路的功率传输效率&#xff0c;还与电磁兼容性&#xff08;EMC&#xff09;、热管理以及电路的可靠性密切相关。 1. 走线布局 在进行变压器下方走线设计时&#xff0c…

Ubuntu 实时查看显存调用命令 free 及命令详解与原理说明(全)

Ubuntu 实时查看显存调用命令 free 及详解 文章目录 Ubuntu 实时查看显存调用命令 free 及详解1 free 作用1.1 语法&#xff1a;1.2 单独显示例子1.3 组合显示例子 2 输出介绍3 原理解释3.1 buff / cache&#xff08;即 buffer / cache&#xff09;3.1.1 buffer 缓冲区3.1.2 ca…