最近做东西用到了大量动态组件相关的知识,先总结一下一种比较简单的。
已经有了一个组件,AppComponent,也有一个将要动态创建的组件MsgComponent,
@Component({
selector: 'msg',
template: `
<h3>{{type}}</h3>
`
})
export class MsgComponent {
type = '123';
}
那么就得有个地方“放”这个动态创建出来的组件,这个地方就叫做容器(container),AppComponent中的容器是这样子的:
template: `
<h1 #msgContainer>我是Container</h1>
`,
然后在AppComponent中拿到这个容器:
@ViewChild('msgContainer', {read: ViewContainerRef}) container;
ViewChild挺强大的;参数设置成ViewContainerRef用来控制container这个变量的类型,视图容器类型。
ViewContainerRef的文档在这里
abstract class ViewContainerRef {
...
abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>
...
}
如此一来,container这个实例上就可使用createComponent方法来创建组件了。这个方法的参数比较多,但是只有第一个参数是必须的,别的我也没用过。
第一个参数是一个ComponentFactory的实例,
打一个比喻:container好比是一个小程序员,他有写代码的能力,这个能力叫做createComponent,但是他不知道具体怎么写,他得看需求文档,这个文档就是一个ComponentFactory实例。如何得到这个实例?
组件工厂解析器:ComponentFactoryResolver
组件工厂解析器可以产生一个组件工厂(ComponentFactory),在AppComponent中通过依赖注入获得一个组件工厂解析器:
constructor(private resolver: ComponentFactoryResolver) {
}
然后就可以创建一个组件工厂,之后交给容器根据这个工厂来创建组件:
const factory: ComponentFactory<MsgComponent> = this.resolver.resolveComponentFactory(MsgComponent);
this.componentRef = this.container.createComponent(factory);
AppComponent的代码如下:
@Component({
selector: 'my-app',
template: `
<h1 #msgContainer>我是Container</h1>
<button (click)="createComponent()">来一个</button>
`,
entryComponents: [MsgComponent], // 或者加到模块中也可以
})
export class AppComponent {
@ViewChild('msgContainer', {read: ViewContainerRef}) container;
componentRef: ComponentRef<MsgComponent>;
constructor(private resolver: ComponentFactoryResolver) {
}
createComponent() {
const factory: ComponentFactory<MsgComponent> = this.resolver.resolveComponentFactory(MsgComponent);
this.componentRef = this.container.createComponent(factory); // Internally this method will call the create() method from the factory and will append the component as a sibling to our container.
console.log('componentRef',this.componentRef);
this.componentRef.instance.type = Math.random() + '';
}
}
通过componentRef就可以拿到新建的组件实例了:
从上图中可以看到,新的组件被追加到了容器中,如果希望清空容器,可以创建组件之前调用:
this.container.clear();
参考文献:
https://netbasal.com/dynamically-creating-components-with-angular-a7346f4a982d