在 Angular 2 中打印 Html 模板(Angular 2 中的 ng-print)

Posted

技术标签:

【中文标题】在 Angular 2 中打印 Html 模板(Angular 2 中的 ng-print)【英文标题】:Print Html template in Angular 2 (ng-print in Angular 2) 【发布时间】:2017-05-13 18:05:05 【问题描述】:

我想在 angular 2 中打印 html 模板。我对此进行了探索,我在 angularjs 1 Print Html Template in Angularjs 1 中得到了解决方案@

任何建议将不胜感激

【问题讨论】:

【参考方案1】:

你可以在 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>

【讨论】:

您的答案需要更正,您非常接近。感谢您的快速回复,我赞成回答:) 其实这个答案我没有测试,我会尽快更新的 我已经更新了它,它对我有用。测试一下,如果需要,进行更正 如果我在文本中输入任何文本,则认为它没有打印 @VikashDahiya 先生,我使用了上面的代码,但我在 line-window 中收到了 null。打开它返回的 null ..【参考方案2】:

这就是我在 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%,');
    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)和更多开箱即用的可控和安全打印案例。

【讨论】:

如果 printContents 出现在原始站点屏幕中,有没有办法轻松包含样式? @amit 其实我没想过。 @selemmn 我花了很多时间试图弄清楚但没有成功。如果你确实找到了办法,我很想知道 @amit 你能为你的问题提供一个 plunker 吗? @selemmn 这有点难,因为它是一个复杂的 Angular 2 项目,有许多组件和许多样式......【参考方案3】:

打印服务

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);
 


不是最佳选择,但有效。

【讨论】:

这不是要打印整个页面而不是突出那个元素吗? 不要忘记添加 css @media print 并使用显示和可见性来使上述代码正常工作【参考方案4】:

万一其他人遇到这个问题,如果您已经布置了页面,我建议您使用媒体查询来设置您的打印页面。然后,您可以简单地将打印功能附加到您的 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
  .doNotPrintdisplay:none !important;

您还可以选择在媒体查询中添加您不希望打印的其他元素/部分。

您也可以在打印查询中更改文档边距和所有内容,这使得它非常强大。网上有很多文章。这里有一个看起来很全面:https://www.sitepoint.com/create-a-customized-print-stylesheet-in-minutes/ 这也意味着您不必创建单独的脚本来创建页面的“打印版本”或使用大量的 javascript

【讨论】:

您也可以使用 css 中的 :not() 选择器,只在要打印的元素上使用一个类。示例: 要打印的东西 然后在 css 文件上:@media print :not(.print_this)display:none;!important 如何使用它来打印子 div 的内容?分层我有这种情况:MainComponent > DashboardComponent > DivToPrint。这是一个路由器插座链。我如何设置它以使用此@media 查询? @LucaEffeFederzoni 我相信无论您的层次结构如何,只要您适当地标记每个 div,它都可以工作。 IE。在 DashboardComponent 中,将不应打印的所有内容标记为“不打印”,这可能会有点复杂,在这种情况下,您可能想要执行其他人建议的操作,即创建一个用于打印的页面。如果您使用 Angular,为避免重复 CSS,请将不打印规则放在您的 app.component.css 中,并将其添加到您需要的每个组件的 styleUrls 中。 @Farasi78 它确实有效,但不完全有效。我创建了一个指令,打印应用的潜水内容,但打印有点奇怪。顺便谢谢你的帮助,至少我设法进步了。 我正在尝试打印一个有 50 列的表格,但在打印文档模板上它只显示 20 列,其余的都被隐藏了。您能帮我解决这个问题并在单行中显示整个表格的列吗?【参考方案5】:

我发现在不影响样式的情况下解决此问题的最佳选择是为打印输出使用单独的路由并将此路由加载到 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);
  


【讨论】:

【参考方案6】:

编辑:更新了 sn-ps 以获得更通用的方法

作为已接受答案的扩展,

为了让现有样式保留目标组件的外观,您可以:

    进行查询以从***文档中提取 &lt;style&gt;&lt;link&gt; 元素

    将其注入到 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%,');
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

【讨论】:

【参考方案7】:

我遇到了同样的问题并找到了另一种方法。它适用于我的情况,因为它是一个相对较小的应用程序。

首先,用户将在需要打印的组件中单击按钮。这将设置一个可由应用程序组件访问的标志。像这样

.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
   .doNotPrintdisplay:none !important;
 

【讨论】:

【参考方案8】:

Windows 应用程序通常带有内置打印功能,但对于 Web 应用程序,我会选择简单地生成 PDF 文件。

我发现最简单的方法是使用 PDFMake (www.pdfmake.org) 生成一个 PDf 文件。然后,您可以让用户选择打开或下载生成的 PDF 文件。

【讨论】:

【参考方案9】:

将窗口分配给打字稿变量然后调用 print 方法的最短解决方案,如下所示

在模板文件中

<button ... (click)="window.print()" ...>Submit</button>

并且,在打字稿文件中

window: any;
constructor() 
  this.window = window;

【讨论】:

【参考方案10】:

使用库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>

More details

【讨论】:

您能否提供有关自定义 css 文件的详细信息 是的,您可以添加自定义样式或现有样式。检查 ngx-print 文档【参考方案11】:

如果需要打印一些自定义的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>

【讨论】:

以上是关于在 Angular 2 中打印 Html 模板(Angular 2 中的 ng-print)的主要内容,如果未能解决你的问题,请参考以下文章

Angular模板简介

angular 2 包含 html 模板

Django Python,通过字典并将其内容打印在html模板中

无法使用 Angular js 2 打印数据

在 Angular 中打印 [object HTMLElement]

webpack html-loaders 小写 angular 2 内置指令