window.print() 前端实现网页打印详解

前言
print作为浏览已经比较成熟的技术可以经常被用来打印页面的部分内容,我们可以在MDN上查看到相关的简单介绍。

一、print()方法

print() 方法用于打印当前窗口的内容。调用 print() 方法会产生一个打印预览弹框,让用户可以设置打印请求。最简单的打印就是直接调用window.print(),当然用 document.execCommand(‘print’) 也可以达到同样的效果。默认打印页面中body里的所有内容。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>printDemo</title>
</head>
<body><input type="button" value="打印此页面" onclick="printpage()" /><div>内容</div><script>function printpage() {window.print()}</script>
</body>
</html>

在这里插入图片描述

二、打印样式

直接调用print()方法去打印网页内容,我们会发现,事先调整好的布局和样式都没法实现,那么有哪些方法可以帮助我们改善打印的用户体验呢?

【1】使用打印样式表

配置一份打印样式表print.css,引入到HTML文档,在 上加上一个 media=“print” 来标识这是打印机才会应用的样式表,这样打印的时候,就会默认将该样式表应用到文档中

<link href="/path/print.css" media="print" rel="stylesheet" />

【2】使用媒介查询

当我们要修改的样式没有很多的时候,其实完全不需要重新写个样式表,只要写上一个媒介查询也可以达到同样的效果,如:

@media print {h1 {font-size: 20px;color: red;}
}

【3】内联样式使用media属性

<style type="text/css" media="print">// 打印样式
</style>

【4】在css中使用@import引入打印样式表

@import url("/path/print.css") print;

三、打印指定区域部分内容

【1】方法一

在需要打印的正文内容所对应的html开始处加上 标识,结尾处加上 标识,截取打印标识之间的内容替换body的内容,调用打印print()方法。

<body><input type="button" value="打印此页面" onclick="printpage()" /><!--startprint--><div id="printContent">打印内容</div><!--endprint--><script>function printpage() {let oldStr = window.document.body.innerHTML; // 获取body的内容let start = "<!--startprint-->"; // 开始打印标识, 17个字符let end = "<!--endprint-->"; // 结束打印标识let newStr = oldStr.substr(oldStr.indexOf(start) + 17); // 截取开始打印标识之后的内容newStr = newStr.substring(0, newStr.indexOf(end)); // 截取开始打印标识和结束打印标识之间的内容window.document.body.innerHTML = newStr; // 把需要打印的指定内容赋给bodywindow.print(); // 调用浏览器的打印功能打印指定区域window.document.body.innerHTML = oldStr; // body替换为原来的内容}</script>
</body>

【2】方法二

将需要打印的内容用一个大的div包裹,打印时将body的内容替换为该div的内容,调用打印print()方法。


<body><input type="button" value="打印此页面" onclick="printpage()" /><div id="printContent">打印内容</div><script>function printpage() {let newstr = document.getElementById("printContent").innerHTML;let oldstr = document.body.innerHTML;document.body.innerHTML = newstr;window.print();document.body.innerHTML = oldstr;return false;}</script>
</body>

【3】方法三

有两个事件可以监听到到打印事件,一个是onbeforeprint(),一个是onafterprint(),分别表示打印事件触发前后。

检测打印请求,提供一个打印前的处理事件onbeforeprint() 将一些不需要打印的元素隐藏,和打印后的处理事件 onafterprint()放开隐藏的元素

	window.onbeforeprint = function(event) {//将一些不需要打印的元素隐藏};window.onafterprint = function(event) {//放开隐藏的元素};

四、强制插入分页

【1】page-break-before(指定元素前添加分页符)

描述
auto默认值。如果必要则在元素前插入分页符。
always在元素前插入分页符。
avoid避免在元素前插入分页符。
left在元素之前足够的分页符,一直到一张空白的左页为止。
right在元素之前足够的分页符,一直到一张空白的右页为止。
inherit规定应该从父元素继承 page-break-before 属性的设置。
/* 在h1元素前始终插入分页符 */
@media print {h1 {page-break-before: always;}
}

【2】page-break-after(指定元素后添加分页符)

描述
auto默认值。如果必要则在元素后插入分页符。
always在元素后插入分页符。
avoid避免在元素后插入分页符。
left在元素之后足够的分页符,一直到一张空白的左页为止。
right在元素之后足够的分页符,一直到一张空白的右页为止。
inherit规定应该从父元素继承 page-break-after 属性的设置。
/* 在 .footer 元素后始终插入分页符 */
@media print {.footer {page-break-after: always;}
}

【3】page-break-inside(用于设置是否在指定元素中插入分页符)

描述
auto默认。如果必要则在元素内部插入分页符。
avoid避免在元素内部插入分页符。
inherit规定应该从父元素继承 page-break-inside 属性的设置。
/* 避免在 <pre> 与 <blockquote> 元素中插入分页符 */
@media print {pre, blockquote {page-break-inside: avoid;}
}

【4】注意

不能对绝对定位的元素使用以上三种分页属性。
请尽可能少地使用分页属性,并且避免在表格、浮动元素、带有边框的块元素中使用分页属性。

五、设置打印布局(横向、纵向、边距)

@media print {@page {/* 纵向 */size: portrait; /* 横向 */size: landscape;/* 边距 上右下左 */margin: 1cm 2cm 1cm 2cm;}}

六、去除浏览器默认页眉页脚

页眉打印默认有页眉页脚信息,展现到页面外边距范围,我们可以通过去除页面模型page的外边距,使得内容不会延伸到页面的边缘,再通过设置 body 元素的 margin 来保证 A4 纸打印出来的页面带有外边距

@media print {@page {margin: 0;}body {margin: 1cm;}
}

七、打印方法封装

【1】封装:在utils下新建print.js文件

export default function printHtml(html) {let style = getStyle();let container = getContainer(html);document.body.appendChild(style);document.body.appendChild(container);getLoadPromise(container).then(() => {window.print();document.body.removeChild(style);document.body.removeChild(container);});
}// 设置打印样式
function getStyle() {
let styleContent = `#print-container {display: none;
}
@media print {body > :not(.print-container) {display: none;}html,body {display: block !important;}#print-container {display: block;}
}`;let style = document.createElement("style");style.innerHTML = styleContent;return style;
}// 清空打印内容
function cleanPrint() {let div = document.getElementById('print-container')if (!!div) {document.querySelector('body').removeChild(div)}
}// 新建DOM,将需要打印的内容填充到DOM
function getContainer(html) {cleanPrint()let container = document.createElement("div");container.setAttribute("id", "print-container");container.innerHTML = html;return container;
}// 图片完全加载后再调用打印方法
function getLoadPromise(dom) {let imgs = dom.querySelectorAll("img");imgs = [].slice.call(imgs);if (imgs.length === 0) {return Promise.resolve();}let finishedCount = 0;return new Promise(resolve => {function check() {finishedCount++;if (finishedCount === imgs.length) {resolve();}}imgs.forEach(img => {img.addEventListener("load", check);img.addEventListener("error", check);})});
}

【2】使用: 引入print文件,传入需要打印的DOM元素

import printHtml from "@/utils/print.js"export default {methods: {print() {let printData = `<div>打印内容</div>`printHtml(printData)}},
}

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

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

相关文章

判断一个数的二进制形式是否只有一个1,是的话就输出

// 判断一个数的二进制形式是否只有一个1&#xff0c;是的话就输出#include "stdafx.h" #include <stdlib.h>int main(int argc, char* argv[]) {unsigned int n 0;char str[100] {0};do{if(n && (n & (n-1)) 0){printf("%d, %X\n", …

android- Auto Monitor Logcat

启动模拟器的时候弹出窗体&#xff1a; 它实在询问你是否显示logcat视图以便显示此工作空间中的程序信息。 因为如何程序错误&#xff0c;可以从logcat中看到错误的原因&#xff0c;建议选择yes。 单击确定&#xff0c;你会发现多了一个Logcat窗体。转载于:https://www.cnblogs…

C#2.0泛型

泛型是什么 一种类型占位符&#xff0c;或称之为类型参数。我们知道在一个方法中&#xff0c;一个变量的值可以作为参数&#xff0c;但其实这个变量的类型本身也可以作为参数。泛型允许我们在调用的时候再指定这个类型参数是什么。在.net中&#xff0c;泛型能够给我们带来的两…

css行高line-height的一些深入理解及应用

1. 一些字面意思 “行高”是指两行文字间基线之间的距离。基线是在英文字母中用到的一个概念&#xff0c;我们刚学英语的时使用的那个英语本子每行有四条线&#xff0c;其中底部第二条线就是基线&#xff0c;是a,c,z,x等字母的底边线。下图的红色线即为基线 2. line-height与l…

echarts使用大总结

echarts图表x轴数据太多显示不全的问题 问题如图&#xff0c;x轴数据条数过多可能导致x轴显示不全&#xff0c;开始我使用下面方法 xAxis: {type: "category",min: min,max: max,data:time,axisLabel: {interval:num,//interval为x轴两相邻数据之间所包含数据条数&a…

宏定义中##和#的作用

From: http://blog.chinaunix.net/space.php?uid16135252&doblog&id2752917 内核中有很多的宏定义&#xff0c;在宏定义define中经常看到两个字符串##和#&#xff0c;这里把它的用法做一下说明&#xff1a; ##是一个连接符号&#xff0c;用于把参数连在一起 …

我对CSS vertical-align的一些理解与认识(一)

1. vertical-align一大堆乱七八糟的属性 有句俗语叫做“见多不怪”&#xff0c;我估摸着这些top,bottom属性大家都见过&#xff0c;没啥看头&#xff0c;没啥说头。老实讲&#xff0c;我看到这些养臭虫的属性也头疼&#xff0c;所以&#xff0c;忘了他们&#xff0c;我们说点有…

@Repository , @Service , @Controller 和 @Component

用Spring MVC时Controller注解的类将变成一个Spring MVC的控制器. 不用Spring MVC的情况下, 这四个注解没有区别. 根据注解的语义, 注解在类上面可以提高代码的可读性.Repository代表仓库. 一般注解在DAO实现类上, 别人看代码时, 就知道这个类是一个跟数据存储有关的类. Servic…

vue的token刷新处理

前言 以token处理登录的web系统&#xff0c;一般会有两个token&#xff1a;access-token和refresh-token。 node.js中&#xff0c;一般用jsonwebtoken这个模块。 access-token&#xff0c;是用户输入登录的账号密码&#xff0c;后台去db验证然后颁发的&#xff0c;它一般记录…

我对CSS vertical-align的一些理解与认识(二)

1. 我对不同浏览器解析vertical-align属性的理解 在上集中&#xff0c;在最后提供的实例中&#xff0c;vertical-align:middle实际上应该是与后面的文字是独立的&#xff0c;毫无关联&#xff0c;就是说vertical-align无论是什么&#xff0c;都不影响文字在box中的位置&#x…

request_do?send方法

Ruby中 respond_to? 和 send 的用法php?nameRuby" class"t_tag">Ruby中 respond_to? 和 send 的用法[收藏] Ruby中的字符串与符号 如同其他的OO语言一样&#xff0c;在ruby中&#xff0c;通过给对象发送消息&#xff0c;来完成对象的功能&#xff0c;比如…

Vue中token刷新及token过期的实现

总&#xff1a;通过axios&#xff0c;vuex&#xff0c;及自定义的方法实现。 以下是思路&#xff1a; 1.做token刷新必不可少的是&#xff0c;token&#xff08;请求时的token&#xff09; / refresh_token&#xff08;刷新token时用的refresh_token&#xff09; / resetTime&a…

Source Code Library 源代码收集器

对于程序员来说&#xff0c;收集、整理一些常用的源代码是经常性的工作&#xff0c;但很多时候&#xff0c;随着收集的代码、文档、压缩包的增长&#xff0c;也会产生另一个问题&#xff1a;那就是如何快速找到所需要的内容。 这个问题曾经困扰着我&#xff0c;后来我开始使用&…

VC2010如何给ActiveX添加事件

利用VC开发ActiveX时&#xff0c;需要给控件添加标准事件或自定义事件&#xff0c;在VC6中有多种方法&#xff1a; 一、按Ctrl W 打开类向导&#xff0d;&#xff1e;切换到“ActiveX Events"&#xff0d;&#xff1e;Add Event...&#xff0c;如图&#xff1a; 二、右…

css动态设置宽高

css 中可以使用 calc() 来动态设置宽高&#xff0c;但是&#xff0c;在表达式中运算符的前后必须要有空格 height:calc(100vh - 80px);

Windows Runtime (RT)

学了sl for wp 开发了1年都没入门&#xff0c;只能说自己的学习欲望太低了。 今天偶然才发现wrt 跟 .net 是2个东西... orz。 得抛弃 sl &#xff0c;wrt才是未来的主流吧... 这篇文章不错 http://www.dotblogs.com.tw/regionbbs/archive/2011/09/18/introducing.windows.runti…