Bootstrap

angular 中 ElementRef、TemplateRef、ViewContainerRef

一个更好理解angular视图的专栏

TemplateRef

用于获取 <ng-template> 元素

用法一:在组件中使用自定义模板

在这里插入图片描述
如上: header 和 footer 需要使用自定义模板

// app.component.ts
import { Component, ElementRef, TemplateRef, ViewChild, ViewContainerRef, ViewRef } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>TemplateRef</h1>
    <app-detail [header]="header" [footer]="footer"></app-detail>

    <ng-template #header>This is header template</ng-template>
    <ng-template #footer>This is footer template</ng-template>
  `
})
export class AppComponent {
  title = 'demo-angular-material';

  @ViewChild('header', { static: true }) headerTemplate: TemplateRef<any>;
  @ViewChild('footer', { static: true }) footerTemplate: TemplateRef<any>;

  constructor() {}

  ngOnInit(): void {}
}

// detail.component.ts
import { Component, Input, OnInit, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-detail',
  template: `
    <ng-container *ngTemplateOutlet="header"></ng-container>
    <div>详情明细...</div>
    <ng-container *ngTemplateOutlet="footer"></ng-container>
  `
})
export class DetailComponent implements OnInit {

  @Input() header: TemplateRef<any>;
  @Input() footer: TemplateRef<any>;

  constructor() { }

  ngOnInit() {}

}

ElementRef

相当于document.querySelector('XX'), 主要用于获取 dom 元素

用法一:获取指定dom

@Component({
  selector: 'app-root',
  template: `
    <h1>ElementRef</h1>
    <div #content>主要内容...</div>
  `
})
export class AppComponent {
  title = 'demo-angular-material';

  @ViewChild('content', { static: true }) content: ElementRef<any>;

  constructor() {}

  ngOnInit(): void {
    console.log(this.content, this.content.nativeElement)
  }
}

在这里插入图片描述

用法二:获取组件 / 指令的整个dom

通过在 构造函数 中注入的方式可以获得整个组件的dom

@Component({
  selector: 'app-root',
  template: `
    <h1>ElementRef</h1>
    <div #content>主要内容...</div>
  `
})
export class AppComponent {
  title = 'demo-angular-material';

  constructor(private elementRef: ElementRef) {}

  ngOnInit(): void {
    console.log(this.elementRef, this.elementRef.nativeElement)
  }
}

在这里插入图片描述

ViewContainerRef

视图容器,包含创建和操作 angular 视图的相关api ( 获取 <ng-container></ng-container>)

angular中有两种视图类型:

  • 插入式视图 Embedded Views
    • 嵌入式视图的引用 EmbeddedViewRef
    • *ngTemplateOutlet
  • 宿主视图 component instance views,即组件实例视图
    • 组件实例视图 引用 ComponentRef
    • *ngComponentOutlet

ViewContainerRef中提供了两个创建上述两种视图的方法

abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, options?: {
        index?: number;
        injector?: Injector;
    }): EmbeddedViewRef<C>;


abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>;

创建内嵌视图

import { Component, ElementRef, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <h1>ElementRef</h1>
    <div #content>主要内容...</div>

    <ng-template #tpl>
          <span>I am span in template</span>
      </ng-template>
    <ng-container #viewContainer></ng-container>
  `
})

export class AppComponent {
  @ViewChild('tpl', {static: true}) tpl: TemplateRef<any>;
  @ViewChild('viewContainer', {read: ViewContainerRef}) viewContainer: ViewContainerRef;

  constructor() {}

  ngAfterViewInit(): void {
    const embeddedRef = this.tpl.createEmbeddedView(null)
    this.viewContainer.insert(embeddedRef)
    console.log(this.tpl)
  }
}

创建组件实例视图

import { Component, ComponentFactoryResolver, ElementRef, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';
import { DetailComponent } from './detail/detail.component';
@Component({
  selector: 'app-root',
  template: `
    <ng-container #test></ng-container>
  `
})

export class AppComponent {
  @ViewChild('test', {read: ViewContainerRef}) viewContainer: ViewContainerRef;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  ngAfterViewInit(): void {
    const detailComponent = this.componentFactoryResolver.resolveComponentFactory(DetailComponent);
    this.viewContainer.clear()
    this.viewContainer.createComponent(detailComponent);
  }
}
;