原文链接
Understanding ViewChildren, ContentChildren, and QueryList in Angular
使用场景
有时候,我们想要在父组件中访问它的子组件。在Angular中可以使用ViewChildren
ViewChild
ContentChildren
来实现对子组件的访问。
假设,我们封装了一个Alert
子组件
// alert.component.html
<h1 (click)="alert()">{{type}}</h1>
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.scss']
})
export class AlertComponent implements OnInit {
@Input() type = 'success';
constructor() { }
ngOnInit() {
}
alert() {
console.log('alert');
}
}
然后,在HomeComponent 使用它多次
// home.component.html
<app-alert></app-alert>
<app-alert type="info"></app-alert>
<app-alert type="danger"></app-alert>
ViewChildren
使用 @ViewChildren
decorator 来获取所有的子组件。@ViewChildren
支持的参数包括 directive
、component type
和 模板变量。
// home.component.js
export class HomeComponent implements OnInit, AfterViewInit {
@ViewChildren(AlertComponent) alerts: QueryList<AlertComponent>;
ngAfterViewInit() {
console.log(this.alerts);
this.alerts.forEach(alertInstance => console.log(alertInstance));
}
}
控制台打印出了3个AlertComponent的instance 对象
当@ViewChildren
的参数是 component
或者 directive
时,会返回component
或者 directive
的实例对象。
当@ViewChildren
的参数是模板变量时,会分两种情况。如果模板变量对应的是一个component
,则返回实例对象;如果模板变量对应的是一个普通html标签,则返回本地元素的引用 ElementRef
。
// home.component.html
<div class="col" #div>
<app-alert #alert1></app-alert>
<app-alert type="info"></app-alert>
<app-alert type="danger"></app-alert>
</div>
// home.component.ts
export class HomeComponent implements OnInit, AfterViewInit {
@ViewChildren('alert1') alerts: QueryList<any>;
@ViewChildren('div') div: QueryList<any>;
ngAfterViewInit() {
console.log(this.div);
this.div.forEach(inst => console.log(inst));
console.log(this.alerts);
this.alerts.forEach(alertInstance => console.log(alertInstance));
}
}
需要注意的是:如果使用了
*ngIf
来控制子组件是否显示,只有在子组件显示的时候,才能够获取到子组件。
ViewChild
如果在父组件中只有一个子组件,使用@ViewChild
比较合适。
// home.component.ts
export class HomeComponent implements OnInit, AfterViewInit {
@ViewChild('alert1') alerts: any;
@ViewChild('div') div: any;
ngAfterViewInit() {
console.log(this.div);
console.log(this.alerts);
}
}
read 参数
ElementRef
如果不想获取子组件的实例,只想访问Dom元素,可以添加read
参数
// home.component.ts
@ViewChild('alert1', {read: ElementRef}) alerts: any;
@ViewChildren
也支持read 参数。
ViewContainerRef
You need this token when you need to create templates or components dynamically。当需要动态创建组件时,需要这个参数。
@ViewChildren(AlertComponent, {read: ViewContainerRef}) alerts: QueryList<AlertComponent>;