Angular @ViewChild 操作 DOM

Angular About 3,437 words

@ViewChild

基本语法:

@ViewChild([reference from template], {read: [reference type]});

挂载的是span等简单HTML元素,Angular推断为ElementRef类型。

挂载的是template元素(ng-template),Angular推断为TemplateRef类型。

一些引用类型如ViewContainerRef就不可以被Angular推断出来,所以必须在read参数中显式声明。

ElementRef

使用#HTML标签上标记,在Component中使用@ViewChild找到该元素引用。

@Component({
    selector: 'sample',
    template: `
        <span #tref>I am span</span>
    `
})
export class SampleComponent implements AfterViewInit {
    @ViewChild("tref", {read: ElementRef})
    tref: ElementRef;

    ngAfterViewInit(): void {
        // `I am span`
        console.log(this.tref.nativeElement.textContent);
    }
}

可以直接通过依赖注入,获取宿主元素的ElementRef对象。

@Component({
    selector: 'sample',
    ...
export class SampleComponent{
      constructor(private hostElement: ElementRef) {
          // <sample>...</sample>
          console.log(this.hostElement.nativeElement.outerHTML);
      }
}

TemplateRef

TemplateRef是一个结构简单的抽象类(ng-template),它的elementRef属性是对其宿主元素的引用,它还有一个createEmbeddedView方法。createEmbeddedView方法非常有用,因为它可以创建一个视图(view)并返回该视图的引用对象ViewRef

$implicitlet-之间是什么关系?

答:可以通过let-nameng-template上定义局部变量。该name字段只能在ng-template内部使用。

<ng-template let-foo> 
 {{ foo }}
</ng-template>

相当于

<ng-template let-foo="$implicit"> 
  {{ foo }}
</ng-template>

如果不使用$implicit,则需要这样写

<ng-template let-foo='helloWorld'> 
 {{ foo }}
</ng-template>

ts文件

this.tpl.createEmbeddedView({helloWorld: 'this is from demo'})

案例

demo.component.ts

@Component({
    selector: 'app-demo',
    template: `
        <ng-container #vc></ng-container>
        <ng-template #tpl let-data>
            <app-another [data]="data">I am span in template</app-another>
        </ng-template>
    `
})
export class DemoComponent implements OnInit {

    @ViewChild("vc", {static: true, read: ViewContainerRef})
    vc: ViewContainerRef;

    @ViewChild("tpl", {static: true})
    tpl: TemplateRef<any>;

    ngOnInit(): void {
        let view = this.tpl.createEmbeddedView({$implicit: 'this is from demo'});
        this.vc.insert(view);
    }

    ngAfterViewInit() {
        let elementRef = this.tpl.elementRef;
        console.log(elementRef.nativeElement.textContent);
    }

}

another.component.ts

@Component({
  selector: 'app-another',
  template:
      `
        <div>{{data}}</div>
      `,
})
export class ShippingComponent {

  @Input()
  data: any;

  constructor(
  ) { }

}

ViewContainerRef

视图容器可以挂载一个或多个视图。

使用createComponent动态创建Component。(componentFactoryResolver方法已过时)

使用instance.data传递值,这里的instance表示component的实例,而dataAnotherComponent中定义的@Input()字段data

@Component({
    selector: 'app-demo',
    template: `
        <ng-container #vc></ng-container>
    `
})
export class DemoComponent implements OnInit {

    @ViewChild("vc", {static: true, read: ViewContainerRef})
    vc: ViewContainerRef;

    constructor(
        private componentFactoryResolver: ComponentFactoryResolver
    ) {
    }

    ngOnInit(): void {
        // let componentFactory = this.componentFactoryResolver.resolveComponentFactory(AnotherComponent);
        // let componentInstance = this.vc.createComponent<AnotherComponent>(componentFactory);
        let componentInstance = this.vc.createComponent(AnotherComponent);
        componentInstance.instance.data = "from create component";
    }

}

参考

https://zhuanlan.zhihu.com/p/56224354

Views: 1,200 · Posted: 2022-08-19

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓
Today On History
Browsing Refresh