【发布时间】:2017-05-13 18:05:05
【问题描述】:
我想在 angular 2 中打印 HTML 模板。我对此进行了探索,我在 angularjs 1 Print Html Template in Angularjs 1 中得到了解决方案@
任何建议将不胜感激
【问题讨论】:
标签: javascript angularjs angular
我想在 angular 2 中打印 HTML 模板。我对此进行了探索,我在 angularjs 1 Print Html Template in Angularjs 1 中得到了解决方案@
任何建议将不胜感激
【问题讨论】:
标签: javascript angularjs angular
你可以在 Angular 2 中这样做
在ts文件中
export class Component{
constructor(){
}
printToCart(printSectionId: string){
let popupWinindow
let innerContents = document.getElementById(printSectionId).innerHTML;
popupWinindow = window.open('', '_blank', 'width=600,height=700,scrollbars=no,menubar=no,toolbar=no,location=no,status=no,titlebar=no');
popupWinindow.document.open();
popupWinindow.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + innerContents + '</html>');
popupWinindow.document.close();
}
}
在html中
<div id="printSectionId" >
<div>
<h1>AngularJS Print html templates</h1>
<form novalidate>
First Name:
<input type="text" class="tb8">
<br>
<br> Last Name:
<input type="text" class="tb8">
<br>
<br>
<button class="button">Submit</button>
<button (click)="printToCart('printSectionId')" class="button">Print</button>
</form>
</div>
<div>
<br/>
</div>
</div>
【讨论】:
这就是我在 angular2 中所做的(它类似于 plunkered 解决方案)在您的 HTML 文件中:
<div id="print-section">
// your html stuff that you want to print
</div>
<button (click)="print()">print</button>
在您的 TS 文件中:
print(): void {
let printContents, popupWin;
printContents = document.getElementById('print-section').innerHTML;
popupWin = window.open('', '_blank', 'top=0,left=0,height=100%,width=auto');
popupWin.document.open();
popupWin.document.write(`
<html>
<head>
<title>Print tab</title>
<style>
//........Customized style.......
</style>
</head>
<body onload="window.print();window.close()">${printContents}</body>
</html>`
);
popupWin.document.close();
}
您还可以缩短路径并仅使用 ngx-print 库来减少不一致的编码(混合 JS 和 TS)和更多开箱即用的可控和安全打印案例。
【讨论】:
打印服务
import { Injectable } from '@angular/core';
@Injectable()
export class PrintingService {
public print(printEl: HTMLElement) {
let printContainer: HTMLElement = document.querySelector('#print-container');
if (!printContainer) {
printContainer = document.createElement('div');
printContainer.id = 'print-container';
}
printContainer.innerHTML = '';
let elementCopy = printEl.cloneNode(true);
printContainer.appendChild(elementCopy);
document.body.appendChild(printContainer);
window.print();
}
}
我要打印的组件
@Component({
selector: 'app-component',
templateUrl: './component.component.html',
styleUrls: ['./component.component.css'],
encapsulation: ViewEncapsulation.None
})
export class MyComponent {
@ViewChild('printEl') printEl: ElementRef;
constructor(private printingService: PrintingService) {}
public print(): void {
this.printingService.print(this.printEl.nativeElement);
}
}
不是最佳选择,但有效。
【讨论】:
万一其他人遇到这个问题,如果您已经布置了页面,我建议您使用媒体查询来设置您的打印页面。然后,您可以简单地将打印功能附加到您的 html 按钮并在您的组件中调用 window.print();
component.html:
<div class="doNotPrint">
Header is here.
</div>
<div>
all my beautiful print-related material is here.
</div>
<div class="doNotPrint">
my footer is here.
<button (click)="onPrint()">Print</button>
</div>
component.ts:
onPrint(){
window.print();
}
component.css:
@media print{
.doNotPrint{display:none !important;}
}
您还可以选择在媒体查询中添加您不希望打印的其他元素/部分。
您也可以在打印查询中更改文档边距和所有内容,这使得它非常强大。网上有很多文章。这里有一个看起来很全面:https://www.sitepoint.com/create-a-customized-print-stylesheet-in-minutes/ 这也意味着您不必创建单独的脚本来创建页面的“打印版本”或使用大量的 javascript。
【讨论】:
我发现在不影响样式的情况下解决此问题的最佳选择是为打印输出使用单独的路由并将此路由加载到 iframe 中。
我周围的组件显示为一个标签页。
@Component({
template: '<iframe id="printpage" name="printpage" *ngIf="printSrc" [src]="printSrc"></iframe>',
styleUrls: [ 'previewTab.scss' ]
})
export class PreviewTabPage {
printSrc: SafeUrl;
constructor(
private navParams: NavParams,
private sanitizer: DomSanitizer,
) {
// item to print is passed as url parameter
const itemId = navParams.get('itemId');
// set print page source for iframe in template
this.printSrc = this.sanitizer.bypassSecurityTrustResourceUrl(this.getAbsoluteUrl(itemId));
}
getAbsoluteUrl(itemId: string): string {
// some code to generate an absolute url for your item
return itemUrl;
}
}
iframe 仅加载在应用程序中呈现打印组件的打印路由。在此页面中,可能会在视图完全初始化后触发打印。另一种方式可能是父组件上的打印按钮,通过window.frames["printpage"].print(); 触发 iframe 上的打印。
@Component({
templateUrl: './print.html',
styleUrls: [ 'print.scss' ]
})
export class PrintPage implements AfterViewInit {
constructor() {}
ngAfterViewInit() {
// wait some time, so all images or other async data are loaded / rendered.
// print could be triggered after button press in the parent component as well.
setTimeout(() => {
// print current iframe
window.print();
}, 2000);
}
}
【讨论】:
编辑:更新了 sn-ps 以获得更通用的方法
作为已接受答案的扩展,
为了让现有样式保留目标组件的外观,您可以:
进行查询以从顶级文档中提取 <style> 和 <link> 元素
将其注入到 HTML 字符串中。
获取 HTML 标签:
private getTagsHtml(tagName: keyof HTMLElementTagNameMap): string
{
const htmlStr: string[] = [];
const elements = document.getElementsByTagName(tagName);
for (let idx = 0; idx < elements.length; idx++)
{
htmlStr.push(elements[idx].outerHTML);
}
return htmlStr.join('\r\n');
}
然后在已有的sn-p中:
const printContents = document.getElementById('print-section').innerHTML;
const stylesHtml = this.getTagsHtml('style');
const linksHtml = this.getTagsHtml('link');
const popupWin = window.open('', '_blank', 'top=0,left=0,height=100%,width=auto');
popupWin.document.open();
popupWin.document.write(`
<html>
<head>
<title>Print tab</title>
${linksHtml}
${stylesHtml}
^^^^^^^^^^^^^ add them as usual to the head
</head>
<body onload="window.print(); window.close()">
${printContents}
</body>
</html>
`
);
popupWin.document.close();
现在使用现有样式(Angular 组件为自己创建一个铸造样式)以及现有样式框架(例如 Bootstrap、MaterialDesign、Bulma),它应该看起来像现有屏幕的 sn-p
【讨论】:
我遇到了同样的问题并找到了另一种方法。它适用于我的情况,因为它是一个相对较小的应用程序。
首先,用户将在需要打印的组件中单击按钮。这将设置一个可由应用程序组件访问的标志。像这样
.html 文件
<button mat-button (click)="printMode()">Print Preview</button>
.ts 文件
printMode() {
this.utilities.printMode = true;
}
在 app 组件的 html 中,我们隐藏了除 router-outlet 之外的所有内容。类似下面的东西
<div class="container">
<app-header *ngIf="!utilities.printMode"></app-header>
<mat-sidenav-container>
<mat-sidenav *ngIf="=!utilities.printMode">
<app-sidebar></app-sidebar>
</mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
</div>
通过类似的 ngIf 条件,我们也可以调整组件的 html 模板,使其在 printMode 中只显示或隐藏东西。这样用户在单击打印预览时只会看到需要打印的内容。
我们现在可以使用以下代码简单地打印或返回正常模式
.html 文件
<button mat-button class="doNotPrint" (click)="print()">Print</button>
<button mat-button class="doNotPrint" (click)="endPrint()">Close</button>
.ts 文件
print() {
window.print();
}
endPrint() {
this.utilities.printMode = false;
}
.css 文件(这样打印和关闭按钮就不会被打印出来)
@media print{
.doNotPrint{display:none !important;}
}
【讨论】:
Windows 应用程序通常带有内置打印功能,但对于 Web 应用程序,我会选择简单地生成 PDF 文件。
我发现最简单的方法是使用 PDFMake (www.pdfmake.org) 生成一个 PDf 文件。然后,您可以让用户选择打开或下载生成的 PDF 文件。
【讨论】:
将窗口分配给打字稿变量然后调用 print 方法的最短解决方案,如下所示
在模板文件中
<button ... (click)="window.print()" ...>Submit</button>
并且,在打字稿文件中
window: any;
constructor() {
this.window = window;
}
【讨论】:
使用库ngx-print。
安装:
yarn add ngx-print
or
npm install ngx-print --save
改变你的模块:
import {NgxPrintModule} from 'ngx-print';
...
imports: [
NgxPrintModule,
...
模板:
<div id="print-section">
// print content
</div>
<button ngxPrint printSectionId="print-section">Print</button>
【讨论】:
如果需要打印一些自定义的HTML,可以使用这个方法:
ts:
let control_Print;
control_Print = document.getElementById('__printingFrame');
let doc = control_Print.contentWindow.document;
doc.open();
doc.write("<div style='color:red;'>I WANT TO PRINT THIS, NOT THE CURRENT HTML</div>");
doc.close();
control_Print = control_Print.contentWindow;
control_Print.focus();
control_Print.print();
html:
<iframe title="Lets print" id="__printingFrame" style="width: 0; height: 0; border: 0"></iframe>
【讨论】: