一般信息填写类的需求页面,都会增设「预览」和「打印」功能。我们会通过编写 DOM 及样式来绘制出预览视图,而打印则是基于预览来生成 PDF 文件。
浏览器原生 API window.print() 可以用于打印当前窗口(window.document)视图内容。调用此方法会产生一个打印预览弹框,用户可以根据具体设置来得到打印结果。
接下来将从 code 层面带领大家熟悉「打印」的使用。
默认情况下,基于页面上的内容,会将元素,布局和样式都进行打印;
如果仅想在打印上设置特殊样式,可以通过以下方式:
1.使用打印样式表:
<link href="print.css" media="print" rel="stylesheet" />
2.使用媒介查询:
@media print {p{color: lavender;background: #ccc;}h1{color: lightblue;background: #ccc;}
}
3.使用内联 media 属性
<style media="print"> p{color: lavender;background: #ccc;}h1{color: lightblue;background: #ccc;} </style>
默认情况下,元素的背景色不会被打印,可通过设置属性来支持:
div{// Chrome、Safari 等 webkit 浏览器内核-webkit-print-color-adjust: exact;// 火狐print-color-adjust: exact;color-adjust: exact;
}
默认情况下,调用 window.print() 会对整个 document.body 进行打印,当需要打印指定容器内容时,可以通过以下几种方式:
<body><div id="container"><p>这是一个段落</p><h1>这是一个标题</h1></div><input type="button" value="打印此页面" onclick="printpage()" /><script> const printpage = () => {let newstr = document.getElementById("container").innerHTML;let oldstr = document.body.innerHTML;document.body.innerHTML = newstr;window.print();document.body.innerHTML = oldstr;} </script>
</body>
当只需要打印容器内某一部分内容时,可以通过注释标识进行截取。
<body><div id="container"><!--startprint--><p>这是一个段落</p><!--endprint--><h1>这是一个标题</h1></div><input type="button" value="打印此页面" onclick="printpage()" /><script> const 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>
通过监听打印前后事件,对不需要进行打印的元素进行隐藏和放开隐藏。
<body><div id="container"><p>这是一个段落</p><h1 id="title">这是一个标题</h1></div><input type="button" value="打印此页面" onclick="printpage()" /><script> const printpage = () => {window.print();}window.onbeforeprint = function() {// 将一些不需要被打印的元素隐藏document.getElementById('title').style.display = 'none';}window.onafterprint = function() {// 放开隐藏的元素document.getElementById('title').style.display = 'block';} </script>
</body>
上面几种方式都在当前窗口进行打印,并且都需要更改 document.body 内容,这会出现视图切换,带来的体验不是太好。
下面我们借助 iframe 来实现打印,并且不影响当前视窗的内容展示。
<body><div id="container"><p>这是一个段落</p><h1 id="title">这是一个标题</h1></div><input type="button" value="打印此页面" onclick="printpage()" /><script> const printpage = () => {const printContent = document.querySelector('#container').innerHTML;const iframe = document.createElement('iframe');iframe.setAttribute('style', 'position: absolute; width: 0; height: 0;');document.body.appendChild(iframe);const iframeDoc = iframe.contentWindow.document;// 设置打印展示方式 - 横向展示iframeDoc.write('<style media="print">@page {size: landscape;}</style>');// 向 iframe 中注入 printContent 样式iframeDoc.write(`<link href="./print.css" media="print" rel="stylesheet" />`);// 写入内容iframeDoc.write('<div>' + printContent + '</div>');setTimeout(function(){iframe.contentWindow?.print();document.body.removeChild(iframe);}, 50);} </script>
</body>
值得注意的是,iframe 是一个新的 window 窗口,不会复用当前窗口的样式,需要为 iframe 注入打印内容所需的样式。
当需要自定义打印分页时机时,可通过如下方式将指定 DOM 设为分割点。
1.在指定元素前添加分页符
@media print {h1 {page-break-before: always;}
}
2.在指定元素后添加分页符
@media print {h1 {page-break-after: always;}
}
1.设置打印布局
@media print {@page {/* 纵向展示(高度展示内容更多) *//* size: portrait;*//* 横向(宽度展示内容更大) */size: landscape;/* 打印的边距 上右下左 */margin: 1cm 2cm 1cm 2cm;}
}
注意,一旦设置为 size: landscape,在打印时将不能切换展示模式,包括纸张类的设置。
有一个信息填写页面,支持进行预览和打印,预览是一个 Dialog 弹框,打印取自于预览的内容。因此,在打印前,需要将预览内容呈现在 DOM 树上。
const printFocus = () => { // 打印事件// 1. 挂载要打印的内容setPreviewOpen(true);setTimeout(() => { // 延迟,等待 Dialog 渲染在 DOM 树上// 2. 隐藏要打印的内容const container = document.querySelector('.preview-wrapper');container.setAttribute('style', 'display: none;');// 3. 创建 iframeconst iframe = document.createElement('iframe');const printContent = container.innerHTML;iframe.setAttribute('style', 'position: absolute; width: 0; height: 0;');document.body.appendChild(iframe);const doc = iframe.contentWindow.document;// 4. 写入内容// doc.write('<style media="print">@page {size: landscape;}</style>');doc.write(`<link href="./preview-focus.css" media="print" rel="stylesheet" />`);doc.write('<div>' + printContent + '</div>');const link = doc.getElementsByTagName('link')[0];link.onload = () => { // 样式文件加载完毕后打印// 5. 执行打印iframe.contentWindow?.print();// 6. 重置工作document.body.removeChild(iframe);setPreviewOpen(false);container?.removeAttribute('style');}}, 0);
}
通常我们会遇到这种情况:在打印内容多于一页时会自动进行分页,若分页的分割点恰巧是一行文字,就会出现文字被切割分别显示在上下两页。
尽管我们可以通过 CSS 属性 page-break-before: always; 来干预分页,但页面内容并非固定的,如何将这个属性恰巧应用在分割点的 DOM 元素之上呢?
下面有一个思路可以参考一下:
1.为可能会被分割的元素设置自定义属性,用于查找访问;
2.根据打印视窗的每页高度,粗估一个高度值,作为页面分割的参考;
3.遍历可分割元素,判断它们是否处于页面分割位置(top < pageHeight && botton > pageHeight);
4.若处于页面分割位置,为此 DOM 设置分割属性 page-break-before: always;。
代码实现:
<!-- 自定义属性标识 -->
<div key={index} data-ident="page-break" className="module-paragraph">
<script> // 1、获取可能会被分页符分割的元素const pageBreakEles = container?.querySelectorAll("[data-ident = 'page-break']") || [];// 2、定义打印页面的高度,假设粗估后为 877pxconst printPageHeight = 877;// 3、匹配元素,是否处于页面分割线位置Array.from(pageBreakEles).forEach(ele => {const { top, bottom } = ele.getBoundingClientRect();// 根据高度计算元素处于第几页const currentPage = Math.floor(top / printPageHeight);// 处于分页符位置的元素,设置分割属性if ((top - currentPage * printPageHeight) < printPageHeight && (bottom - currentPage * printPageHeight) > printPageHeight) {(ele as HTMLElement).style.setProperty('page-break-before', 'always');}}); </script>
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
classPacketdefinitialize(name,age,number,array)@name=name@age=age@number=number@neighbors=arrayendendp1=Packet.new("n1",5,2,[1,2,3,4])putsp1.name我有上面的代码,但是每当我执行puts语句时,我都会收到nameisnotamethod的错误。我不知道任何其他方式来打印p1的名称。如何打印姓名? 最佳答案 这里的问题是,虽然您拥有实例变量,但您并未使它们可访问。attr_reader:vari
我正在使用mechanize登录网站,然后检索页面。我遇到了一些问题,我怀疑这是由于cookie中的某些值造成的。当Mechanize登录网站时,我假设它存储了cookie。如何通过Mechanize打印出存储在cookie中的所有数据? 最佳答案 代理有一个cookie方法。agent=Mechanize.newpage=agent.get("http://www.google.com/")agent.cookiesagent.cookies.to_scookie返回一个Mechanize::Cookiesobject
我在目录“C:\DocumentsandSettings\test.exe”中有一个文件,但是当我用单引号编写命令时`C:\DocumentsandSettings\test.exe(我无法在此框中显示),用于在Ruby中执行命令,我无法这样做,我收到的错误是找不到文件或目录。我尝试用“//”和“\”替换“\”,但似乎没有任何效果。我也使用过系统、IO.popen和exec命令,但所有的努力都是徒劳的。exec命令还使程序退出,这是我不想发生的。提前致谢。 最佳答案 反引号环境就像双引号,所以反斜杠用于转义。此外,Ruby会将空格解