Angular 5生成HTML而无需渲染

时间:2019-01-20 12:47:12

标签: html angular angular-components

是否可以通过绕过组件所需的所有数据而无需在浏览器视口中实际呈现它的方式从组件生成html文件? 我只想生成一些html代码,以将其发送到从此html生成PDF的后端。

2 个答案:

答案 0 :(得分:1)

我认为您无法做到,因为angular组件的渲染在很大程度上依赖于生命周期挂钩。

不过,我可以想到一种伪造它的方法:

  • 通过代码实例化不可见的组件
  • 将其添加到DOM,因此其行为类似于任何常规组件
  • 获取HTML
  • 最后摧毁它

Here's a working code example

app.module.ts

请注意,我已将PdfContentComponent添加到模块的entryComponents中。 您要从代码实例化的任何组件都是必需的。

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, PdfContentComponent ],
  bootstrap:    [ AppComponent ],
  entryComponents :  [ PdfContentComponent ]
})
export class AppModule { }

pdf-content.component.html

<span>Hello, {{ name }}</span>

pdf-content.component.ts

请注意host: {style: 'display: none'},这将使该组件有效地不可见

@Component({
  selector: 'my-pdf-content',
  templateUrl: './pdf-content.component.html',
  host: {
    style: 'display: none'
  }
})
export class PdfContentComponent implements OnInit  {
  @Input() name: string;
  @Output() loaded: EventEmitter<void> = new EventEmitter<void>();

  constructor(public element:ElementRef) {

  }

  ngOnInit() {
    this.loaded.emit();
  }
}

app.component.html

<button (click)='printPdf()'>Hit me!</button>

<ng-container #pdfContainer>
</ng-container>

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

// the pdf content will be briefly added to this container
@ViewChild("pdfContainer", { read: ViewContainerRef }) container;

constructor(
  private resolver: ComponentFactoryResolver
) {}

  printPdf() {
    // get the PdfContentComponent factory
    const factory: ComponentFactory<any> = this.resolver.resolveComponentFactory(PdfContentComponent);

    // instantiate a PdfContentComponent
    const pdfContentRef = this.container.createComponent(factory);

    // get the actual instance from the reference
    const pdfContent = pdfContentRef.instance;

    // change some input properties of the component
    pdfContent.name = 'John Doe'; 

    // wait for the component to finish initialization
    // and delay the event listener briefly, 
    // so we don't run the clean up in the middle of angulars lifecycle pass
    const sub = pdfContent.loaded
    .pipe(delay(1))
    .subscribe(() => {
        // stop listening to the loaded event
        sub.unsubscribe();
        // send the html to the backend here
        window.alert(pdfContent.element.nativeElement.innerHTML);
        // remove the component from the DOM
        this.container.remove(this.container.indexOf(pdfContentRef));
    })
  }
}

答案 1 :(得分:1)

您可以使用angular提供的Renderer2类。试试这个示例代码;

import { Component, Renderer2, OnInit } from '@angular/core';

....

constructor(private renderer: Renderer2){

}

ngOnInit(){
  const div: HTMLDivElement = this.renderer.createElement('div');
  const text = this.renderer.createText('Hello world!');
  this.renderer.appendChild(div, text);
  console.log(div.outerHTML);
}