1. ViewChild应用场景
- 场景:用于获取组件视图中直接包含的子组件、DOM元素或模板引用变量。例如,在一个父组件模板中有一个子组件
<app-child></app-child>
,父组件想直接访问子组件的方法或属性时,就可以使用 ViewChild
。
2. ContentChild应用场景
- 场景:主要用于获取通过
ng-content
投影到组件中的子组件、DOM元素或模板引用变量。比如,一个自定义组件 <app-container>
内部有 <ng-content></ng-content>
,其他组件如 <app-inside></app-inside>
通过 <app-container><app-inside></app-inside></app-container>
这种方式投影进去,此时在 app-container
组件内可以用 ContentChild
获取 app-inside
组件。
3. 两者区别
- 获取目标不同:
ViewChild
针对组件视图内直接定义的元素或组件;ContentChild
针对通过 ng-content
投影进来的内容。
- 搜索时机不同:
ViewChild
在组件视图初始化时就尝试获取目标;ContentChild
会在内容投影完成后获取目标,所以 ContentChild
可能会稍晚于 ViewChild
获取到目标。
4. 处理动态加载组件情况
- 动态加载组件获取子组件或内容:
- 动态加载组件与ViewChild:如果动态加载组件是通过
ComponentFactoryResolver
创建并添加到视图中的,在组件加载完成后,可以使用 ViewChild
获取加载的组件实例。例如,先定义一个 @ViewChild('dynamicComponent', {read: ViewContainerRef}) dynamicComponent: ViewContainerRef;
,然后在动态加载组件时,const componentRef = this.dynamicComponent.createComponent(this.componentFactory);
,之后就可以通过 componentRef.instance
访问动态加载组件的实例。
- 动态加载组件与ContentChild:对于通过
ng-content
动态投影进来的组件,在投影完成后 ContentChild
能获取到。可以通过 ngAfterContentInit
生命周期钩子函数来确保内容已投影,在此钩子函数内使用 ContentChild
获取目标组件或元素。例如:
import { Component, ContentChild, AfterContentInit } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class ParentComponent implements AfterContentInit {
@ContentChild(ChildComponent) childComponent: ChildComponent;
ngAfterContentInit() {
if (this.childComponent) {
// 可以操作子组件实例
this.childComponent.doSomething();
}
}
}