一般信息填写类的需求页面,都会增设「预览」和「打印」功能。我们会通过编写 DOM 及样式来绘制出预览视图,而打印则是基于预览来生成 PDF 文件。
浏览器原生 API window.print()
可以用于打印当前窗口(window.document)视图内容。调用此方法会产生一个打印预览弹框,用户可以根据具体设置来得到打印结果。
接下来将从 code 层面带领大家熟悉「打印」的使用。
默认情况下,基于页面上的内容,会将元素,布局和样式都进行打印;
如果仅想在打印上设置特殊样式,可以通过以下方式:
1.使用打印样式表:
2.使用媒介查询:
@media print {p{color: lavender;background: #ccc;}h1{color: lightblue;background: #ccc;}
}
3.使用内联 media 属性
默认情况下,元素的背景色不会被打印,可通过设置属性来支持:
div{// Chrome、Safari 等 webkit 浏览器内核-webkit-print-color-adjust: exact;// 火狐print-color-adjust: exact;color-adjust: exact;
}
默认情况下,调用 window.print() 会对整个 document.body 进行打印,当需要打印指定容器内容时,可以通过以下几种方式:
这是一个段落
这是一个标题
当只需要打印容器内某一部分内容时,可以通过注释标识进行截取。
这是一个段落
这是一个标题
通过监听打印前后事件,对不需要进行打印的元素进行隐藏和放开隐藏。
这是一个段落
这是一个标题
上面几种方式都在当前窗口进行打印,并且都需要更改 document.body 内容,这会出现视图切换,带来的体验不是太好。
下面我们借助 iframe 来实现打印,并且不影响当前视窗的内容展示。
这是一个段落
这是一个标题
值得注意的是,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('');doc.write(``);doc.write('' + printContent + '');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;
。
代码实现:
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。
有需要的小伙伴,可以点击下方卡片领取,无偿分享