前端实现打印功能

2023-10-30

目录

方法一:window.print()   

方法二:利用iframe,iframe.contentWindow.print()

方法三:使用第三方库或插件

提供一个完整的范例:

1. 设计打印布局

2. 创建打印版本

3. 使用JavaScript控制打印

4. 提供打印前处理程序

5. 确保打印的兼容性

总结:


前端实现打印功能的方法有很多,大家在网上随便一搜就是一大堆,在这里,我主要选择一个我觉得比较好一点的实现方式来进行解释描述:


方法一:window.print()   


这个命令默认打印整个页面的内容,所以,如果想要实现局部打印功能的话,就要重新给body赋值,并且后续执行完之后再还原回去,这样的话会造成一些非预期的结果,很麻烦,并且在当前也操作,window.document.body的内容重新渲染,打印完会有刷新,影响用户的体验所以不推荐但还是简单介绍一下:

//(1)首先获得元素的html内容(这里建议如果有样式最好是用内联样式的方式)
var newstr = document.getElementById(myDiv).innerHTML;//得到需要打印的元素HTML

//(2)保存当前页面的整个html,因为window.print()打印操作是打印当前页的所有内容,所以先将当前页面保存起来,之后便于恢复。
var oldstr = document.body.innerHTML;//保存当前页面的HTML

//(3)把当前页面替换为打印内容HTML
document.body.innerHTML = newstr;

//(4)执行打印操作
window.print();

//(5)还原当前页面
document.body.innerHTML = oldstr;

方法二:利用iframe,iframe.contentWindow.print()

这个与方法一的区别就是,取消打印后可以完整保留当前访问页面的内容,不需要影响原页面,需要注意的是,在你生成新的iframe内的html时,样式可能会有影响加载不完全(全局样式特别),需要单独引入一些你自己的样式,我比较推荐这个,所以来重点说明一下:

// 1、获取需要打印的部分
const  printArea =  this.getElementById(document.body,"rx-form-container");

// 2、引入打印的专有CSS样式
var strStyleCSS="<link href='/rxform.css' type='text/css' rel='stylesheet'>";
var antdesignCSS="<link href='/antdesign.css' type='text/css' rel='stylesheet'>";
let printCSS=" <link href='/print.css' type='text/css'  rel='stylesheet'> ";

// 3、拼接字符串
var strFormHtml=strStyleCSS  +antdesignCSS + printCSS+"<body>"+domEl.innerHTML+"</body>";

// 4、创建 iframe 标签
var iframe = document.createElement('IFRAME');
var doc = null;
iframe.setAttribute('style','position:absolute;width:0;height:0;left:-500px;top:-500px;');

// 5、浏览器插入 iframe
document.body.appendChild(iframe);
doc = iframe.contentWindow.document;
// 引入打印的专有CSS样式
// doc.write("<LINK rel='stylesheet' type='text/css' href='/print.css'>");
doc.write(printHTML);
doc.close();
iframe.contentWindow.focus();

// 注意:等待加载完调用打印,否则样式外联css显示有问题
iframe.contentWindow.addEventListener('load', function() {
    // 6、开始打印
    iframe.contentWindow.print();
    // 7、删除iframe
    document.body.removeChild(iframe);
})

这样写虽然不会影响原页面,但是需要我们把打印的内容及样式用JS来生成,如果打印的内容很多,或者样式很复杂的话,那就是一个大工程,难免不方便,所以如何解决问题呢?我在查度娘的时候,发现了一种方式:将要打印的内容生成一个图片然后放在iframe中,利用html2canvas 生成截图但是我并未校验(因为本人项目主要是打印表单流程,没有很复杂,嘻嘻),所以,这里我就简单复制一下大佬的,最后也放置了链接,如果有需要也可以去大佬博客看看:

    // 打印账单
    printBill () {
      this.printDisabled = true  // 点击打印按钮禁止重复点击
      setTimeout(_ => {      // 按钮显示为禁止了再去执行截图功能
        html2canvas(this.$refs.reconciliationWrapper, {
          backgroundColor: null,
          scale: 1.3
        }).then((canvas) => {
          let dataURL = canvas.toDataURL('image/png')
          this.$refs.iframe.contentWindow.document.body.innerHTML = ''  // 清空上一次打印的内容
          this.$refs.iframe.contentWindow.document.write('<html><head><style media="print">@page { margin: 0mm 10mm; }body{margin-top: 50px; text-align: center;}</style></head><body><img src=' + dataURL + '></body></html>')
          setTimeout(_ => {
            this.$refs.iframe.contentWindow.print()
          }, 0)
          this.printDisabled = false
        })
      }, 100)
    }

然后将截图放在iframe中的img打印,截图一般会有些模糊,调整html2canvas的参数scale,放大缩小的比例,要根据实际情况调整。

方法三:使用第三方库或插件

除了使用浏览器自带的打印功能外,还可以使用第三方库或插件来实现更高级的打印操作,例如打印指定区域、打印多个页面等。

常用的打印插件有 Print.jshtml2canvasjPrintArea等。这里以 Print.js 为例,演示如何使用该插件实现前端打印功能。

首先,需要在 `head` 标签中引入 `Print.js` 插件:

<head>
  <script src="/path/to/Print.js"></script>
</head>

然后,在页面中需要打印的元素上添加 `class` 属性或 ID 属性:

<div id="print-content">
  <!-- 这里是需要打印的内容 -->
</div>

最后,在触发打印的按钮的点击事件中,使用 `Print.js` 插件的 `printHtml` 方法来触发打印操作:

function onPrint() {
  // 获取需要打印的内容
  const content = document.getElementById('print-content').innerHTML;

  // 调用 printHtml 方法触发打印操作
  window.printHtml({
    printable: content,
    onAfterPrint: function() {
      // 打印完成后的操作
    }
  });
}

在上述代码中,我们使用了 `window.printHtml` 方法来触发打印操作。该方法接受一个配置对象,其中包含需要打印的内容和打印完成后的回调函数。

需要注意的是,使用第三方插件能够提供更为定制化的打印功能,但是在使用前需要对插件的相关文档进行仔细的阅读和熟悉,确保能够正确地使用插件完成打印功能。

提供一个完整的范例:

当用户想要打印页面时,我们可以向用户提供打印功能。而实现页面打印的主要步骤如下:

1. 设计打印布局

在进行打印之前,我们需要首先设计打印布局以确保打印内容能够在有限的纸张大小上清晰地展示。我们需要定义一个专门的打印样式表来控制样式和布局。这个样式表可以包含在主样式表中,也可以在header标签中单独引用。比较重要的是我们需要在这个样式表中使用`@media print` 来为网页在打印模式下设置独立的样式,以适应打印的需求。因为我们的网页布局和打印页面布局还是有很大的区别,如marginpadding等样式设置等。

可以通过一个简单的示例来说明:

@media print {
    /* 隐藏不必须要打印的元素 */
    header, nav, .no-print {
        display: none;
    }
    /* 修改页面大小和边距 */
    @page {
        size: A4 landscape;
        margin: 20mm 10mm 20mm 10mm;
    }
    
    /*在打印模式下添加样式*/
    .table tr td, .table tr th {
        border: 1px solid #ddd;
        padding: 10px;
    }
    /*自定义打印样式*/
    h1 {
        font-size: 24pt;
        color: blue;
    }
}

在这里我们使用 @media print 创建新的样式,确保要打印的布局不同于网页布局,并提供了一些自定义的打印样式,例如字体大小和颜色。

2. 创建打印版本

实现页面打印的另一个关键步骤是创建一个专门用于打印的版本。可以通过以下方式来实现:

  •  让用户选择打印区域。在这种情况下,我们可以提供一个打印按钮将用户选择的部分发送到打印机。我们可以使用 JavaScript 或 jQuery 将所需的元素捕获并在新窗口中打印。
  • 克隆一个指定的区域。通过使用 `clone()` 方法,我们可以克隆指定的区域来创建一个专门用于打印的版本,然后在新窗口中打印。

以下是一个通过克隆来创建打印版本的示例:

function createPrintVersion() {
  // 获取需要打印的内容。
  var content = document.getElementById('printContent').cloneNode(true);

  // 添加打印标记,以便于在新窗口中仅打印必要内容。
  var html = '<html><head><title>打印页面</title>' +
      '<style> @media print { /* 此处与上述样式表一样,可以复用 */ } </style></head><body>' +
      content.innerHTML + '</body></html>';

  // 返回新生成的打印版本。
  return html;
}

在这个示例中,我们定义了一个名为createPrintVersion()的函数,用于创建一个专门用于打印的版本。该函数获取需要打印的内容并将其复制到新标签中,然后添加打印标记和打印样式,以便在新窗口中仅打印必要的内容。最后,该函数返回一个新生成的打印版本。

3. 使用JavaScript控制打印

在用户点击“打印”按钮时,我们需要触发打印功能。为此,我们要实现用 JavaScript 创建了一个打印功能呼叫的链接,在单击该链接时执行打印功能。

function printContent() {
  // 创建打印窗口。
  var printWindow = window.open('', 'PrintWindow', 'height=600,width=800');

  // 获取需要打印的内容。
  var content = document.getElementById('printContent').cloneNode(true);

  // 添加打印标记,以便于在新窗口中仅打印必要内容。
  var html = '<html><head><title>打印页面</title>' +
      '<style> @media print { /* 此处与上述样式表一样,可以复用 */ } </style></head><body>' +
      content.innerHTML + '</body></html>';

  // 在新窗口中输出打印内容。
  printWindow.document.write(html);

  // 等待文档加载完成后再打印。
  printWindow.document.addEventListener('DOMContentLoaded', function() {
    setTimeout(function() {
      printWindow.print();
      printWindow.close();
    }, 500);
  });
}

在此示例中,我们定义了一个名为printContent()的函数,用于创建一个新的打印窗口并获取打印版本。然后,我们在新窗口中输出打印内容,并添加一个事件侦听器来等待文档加载完成后再进行打印和关闭窗口。

此外,我们也可以通过使用现成打印控件和第三方库如 jspdf 等更加便捷地实现打印功能。

第二步和第三步之间的区别是前者仅是生成打印版本,而后者则创建一个新的窗口并自动进行打印。第二步可以将生成的打印版本传递给用户,以供他们手动打印。而第三步则在打印版本生成后自动弹出窗口进行打印,无需用户交互。

4. 提供打印前处理程序

在打印之前,我们可以为用户提供某些选项,例如检查页面元素是否准备好,或者是否已进行必要的复杂计算,或者在开始打印前看一下预览。因此,我们需要在打印之前添加一些前处理程序,并与用户确认这些设置。

5. 确保打印的兼容性

不同浏览器和打印机配置间打印设置会有一定差异,为确保打印刻度和页面排版在不同浏览器下达到最佳效果,我们建议先自己制作一些测试文件进行测试。要注意的是,在不同的操作系统上,打印输出的内容可能会有所不同,这些问题需要适当考虑。我们可以使用 JavaScript 或其他依赖库在不同情况下进行测试和设置以确保适配性。

以上步骤是如何实现页面打印的主要步骤,如此复杂的需求往往需要前端工程师提前考虑好后。

出现的问题:

1、在使用iframe打印时,发现在打印页自动显示了路由地址,可以尝试以下几种方法去除:

  • iframe标签中添加属性:scrolling="no",这样可以禁用iframe中的滚动条,从而避免显示路由地址。
  • 在打印页面的CSS样式中,添加以下样式代码:
@media print {
  .no-print {
    display: none;
  }
}


然后在iframe标签中添加一个class为"no-print"的div元素,这样可以在打印页面中隐藏该元素及其子元素,从而避免显示路由地址。

  • iframe标签中添加属性:sandbox="allow-same-origin",这样可以限制iframe中的脚本只能与父页面同源的脚本通信,从而避免显示路由地址。

总结:

打印的方式很多,大家选择适合自己项目的即可。就像王者荣耀,哈哈哈(肯定会有人突然疑惑,为什么会突然提到游戏,因为前两天我肯开心自己粉丝在增加,但是感觉自己博客不怎么生动,同事就给了我一个建议,可以说说王者荣耀,嘻嘻嘻,第一次说,以后不一定啥时候说),所以最后总结只有第一句话有用,后边大家随便看看就行,代码机器们,加油,在努力个四五十年,马上就可以退休了!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

前端实现打印功能 的相关文章

  • 【ES6】学ES6一篇就够了

    ES6 let 声明变量 let 关键字声明变量是在 es6 中引入的 使用 let 声明变量主要有以下特点 使用 let 声明的变量具有块级作用域 使用 let 声明的变量没有变量提升 使用 let 声明的变量具有暂时性死区 let 声明
  • 编译原理书籍推荐

    大学课程为什么要开设编译原理呢 这门课程关注的是编译器方面的产生原理和技术问题 似乎和计算机的基础领域不沾边 可是编译原理却一直作为大学本科的必修课程 同时也成为了研究生入学考试的必考内容 编译原理及技术从本质上来讲就是一个算法问题而已 当
  • Unity3D 鼠标控制角色移动与奔跑

    最新补充 一般在做鼠标选择时是从摄像机向目标点发送一条射线 然后取得射线与对象相交的点来计算3D目标点 后来在开发中发现了一个问题 射线被别的对象挡住了 就是如果主角的前面有别的游戏对象挡着 此时如果使用射线的原理 鼠标选择被档的对象 这样

随机推荐

  • Java高效开发-远程debug

    1 前言 这怎么回事 在本地还好好 放到服务器就不行了 这该怎么排查 日志也看不出来啥呀 日常开发中经常会出现这种问题 这时候就可以尝试idea远程debug的模式试试 2 使用 1 环境 idea2021 2 idea配置 重点 将自动生
  • 解决Could not find artifact com.oracle:ojdbc7:pom:12.1.0.2 的方案

    1 试了很多方法 不行 2 最终方案 使用私服nexus解决 3 idea创建maven项目 引入lib文件夹 3 1 打包后上传到私服 坐标为
  • Windows10+Python3.6+创建虚拟环境+pycharm+mySQL+flask (一)

    1 安装Python3 6 首先下载python3 6 https www python org getit 在官网上 下下来之后可以在你的下载路径里面找到 我是64位的操作系统 双击安装 这里注意一下要选择 Add Python3 6 t
  • umi——02——mook和反向代理(跨域)

    1 测试mock的简单使用 首先我们在mock文件夹创建一个文件 文件名随便取 写上这样一段代码 代表Get请求 在登录组件Login中发起请求 启动项目 并在项目的url地址输入 users 就可以看到 2 登录案例 api js exp
  • Linux磁盘配额配置

    磁盘配额配置 1 理解磁盘配额的作用 2 掌握磁盘配额工具 3 掌握磁盘配额配置的方法 任务 账号为user 密码为123456的用户磁盘限额情况如下 user用户能够取得80KB的磁盘使用量 hard 文件数量为5个 只要容量使用超过30
  • java 文件下载进度条_下载文件时显示动态的进度条(前端easyUI,后台java)

    最近有点闲 我们的架构师让我在文件下载时显示进度条 咳咳 自从组里来了前端妹纸后 好久没写前端代码了 架构师推荐的用监听器 链接找不到了 实现得有点复杂 我没太看懂 继续百度 看到了 在下载时计算进度 然后把进度放到session中 另外写
  • 查看哪个进程占用了8005端口,并杀死占用端口的进程。

    查看哪个进程占用了8005端口 netstat ano findstr 8005 返回进程号 通过进程号杀死占用端口的进程 taskkill PID 19288 F 杀死该进程 F是强制删除
  • C++—返回值优化

    返回值优化 Return value optimization 缩写为RVO 是C 的一项编译优化技术 即删除保持函数返回值的临时对象 这可能会省略两次复制构造函数 当一个函数返回一个对象实例 一个临时对象将被创建并通过复制构造函数把目标对
  • 这些Android面试题,成就你高薪就业。

    前言 这些题目都是面试必答题 看看你还有哪些是没有掌握到的 1 说下你所知道的设计模式与使用场景 建造者模式 观察者模式 代理模式 门面模式 单例模式 生产者消费者模式 2 Java语言的特点与OOP思想 这个通过对比来描述 比如面向对象和
  • Leetcode 95. 不同的二叉搜索树 II

    文章目录 题目 代码 9 21 首刷看解析 题目 Leetcode 95 不同的二叉搜索树 II 代码 9 21 首刷看解析 class Solution public vector
  • vue实现动态路由--后台返回路由表(并解决页面刷新,路由找不到的问题)

    先大致说一下自己的思路 其实后台返回的权限表跟我们前端自己配置的路由格式是差不多的 格式可以跟后台沟通 我们需要做的是根据后台返回的路由 然后进行遍历 生成一个本地的路由表 然后利用Router addRouters 这个方法 把我们新生成
  • Jmeter-Android手机端脚本录制

    温馨提示 电脑和手机在同一网络段上 1 打开Jmeter工具 新建一个HTTP代理服务器 2 然后再新建一个线程组 3 在线程组中添加录制控制器 4 打开模拟器 设置 WiFi 长按 修改网络
  • 辅助模块加速收敛,精度大幅提升 移动端实时的NanoDet-Plus来了

    Nanodet目标检测模型完成自动捡球机器人 从零开始 带你用Nanodet目标检测模型完成自动捡球机器人 古月居 开源地址 https github com Coolog Nanodet Robot PathPlanning 作者提出 N
  • 技术分享|SQL和 NoSQL数据库之间的差异:MySQL(VS)MongoDB

    技术分享 SQL和 NoSQL数据库之间的差异 什么是SQL和NoSQL 一 什么是SQL 二 什么是NoSQL SQL VS NoSQL 针对SQL和NoSQL的区别 将基于不同的方面进行比较 MySQL VS MongoDB 在当今市场
  • forEach()退出循环的方法

    在for循环中退出循环有3种方式 return 终止 break 退出整个循环 continue 退出当次循环 forEach 只能识别上面三种退出循环中的return 其它都识别不了 且return在forEach 中相当于continu
  • ThreadLocal失效

    在JDK中 解决线程冲突问题 有两种解决方案 l 给临界区加锁 l 本地化临界区 第一种解决方案的典型代表是Synchonized 第二种的典型代表是ThreadLocal 而CopyOnWrite是这两种方案的融合 ThreadLocal
  • Arduino通过L298N红板控制板控制直流电机

    在Arduino论坛上看到很多人都做过智能小车 有两轮的 有四轮的 功能也是多种多样 有寻迹 壁障 无线遥控 红外遥控的 其实小车就是个底盘或者载体 然后可以根据需要向小车上加功能模块 于是我在淘宝上买了一个四轮小车的架子 里面包括四个轮子
  • python解包的概念_如何以编程方式为解包结构?

    我试图用Python读取和解析一个二进制文件 在 问题是文件中的数据可以是little endian或big endian格式 也可以是32位或64位的值 在文件头中有几个字节指定数据格式和大小 假设我已经读过这些 并且知道格式和大小 然后
  • SWM32系列教程7-I2C及其应用

    SWM32S单片机有2个I2C外设 其特点如下 支持最高1MHZ速率主机模式 支持最高400KHZ速率从机模式 支持7位或10位地址 波特率可配置 支持中断功能 今天就以驱动电容触摸芯片GT911为例 介绍一下I2C模块的使用 配置I2C之
  • 前端实现打印功能

    目录 方法一 window print 方法二 利用iframe iframe contentWindow print 方法三 使用第三方库或插件 提供一个完整的范例 1 设计打印布局 2 创建打印版本 3 使用JavaScript控制打印