angular dynamic component 笔记

使用到动态组件是因为我在做一个Table的控件,表格中有按钮等控件,并具有相应逻辑,同时项目中多处使用到该表格,故想提取一个可复用的控件以减少工作量。主要参考的文章是大神的修仙之路Angular 4.x 动态创建组件以及官方文档Dynamic Component Loader

这里主要简要记录一下我自己的理解。

动态组件的创建

  • 在/src/app目录下通过以下命令可以创建一个简单的TestComponent
ng generate component test
  • 对应需要引用该动态组件的父组件(eg: ParentComponent),首先我们要将TestComponent引入其对应的ParentModule
import { TestComponent } from '.../test.component'
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    ...
  ],declarations: [ ...,TestComponent ],entryComponents: [TestComponent]
})

*注意最后我们用了一个entryComponent的命令,这是因为一般而言,angular编译器会根据代码自动生成所有组件的ComponentFactory,但对于动态插入的组件,其在父组件的代码中没有对于的模板选择器(eg:<test></test>),故为了能让编译器能生成动态组件的ComponentFactory,需要人手告诉angular去生成

Generally,the Angular compiler generates a ComponentFactory for any component referenced in a template. However,there are no selector references in the templates for dynamically loaded components since they load at runtime.

To ensure that the compiler still generates a factory,add dynamically loaded components to the NgModule's entryComponents array:

*ComponentFactory代码定义如下,我的理解它是angular编译得出的js方法,交给浏览器运行,从而用来实际创建组件;

class ComponentFactory<C> {
  get selector: string
  get componentType: Type<any>
  get ngContentSelectors: string[]
  get inputs: {...}
  get outputs: {...}
  create(injector: Injector,projectableNodes?: any[][],rootSelectorOrNode?: string | any,ngModule?: NgModuleRef<any>): ComponentRef<C>
}

*entryComponent则告诉angular编译器,在用户交互过程中,需要动态生成某个组件,故命令angular生成该组件的ComponentFactory,以供后续组件的动态创建使用。
*导入CommonModule,是为了其后使用ngIf,ngFor,<ng-template>等指令。

...
import { ViewContainerRef,AfterViewInit,ViewChild,ComponentFactoryResolver} from '@angular/core';
import { TestComponent } from '.../test.component'
...
export class ParentComponent{
  @ViewChild("Container",{ read: ViewContainerRef }) vcRef: ViewContainerRef;
  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
  ...
  ngAfterViewInit() {
     let componentFactory = this.componentFactoryResolver.resolveComponentFactory(TestComponent);
     this.vcRef.clear();
     let dynamicComponent =  vcRef.createComponent(componentFactory);
     ...
  }
}
<ng-template #Container></ng-template>

*ViewContainerRef 类型代表装载视图的容器类

Represents a container where one or more Views can be attached

*ViewChild用于获取对应ViewContainerRef中的第一个元素或对应的ViewContainerRef实例

You can use ViewChild to get the first element or the directive matching the selector from the view DOM. If the view DOM changes,and a new child matches the selector,the property will be updated.

*此处利用定义html锚点#container,当实例化ViewChild时,传入第一个参数为锚点名字“container”,第二个参数{read: <Type>}为查询条件,设置查询的类型,此处设置返回ViewContainerRef的实例;

*componentFactoryResolver提供生成componentFactory的方法

*由于ViewChild所进行的视图查询是在ngAfterViewInit前调用的,所以对vcRef的操作要在ngAfterViewInit后进行,否则vcRef是undefined,最后利用vcRef的createComponent方法,根据生成的componentFactory,可动态组件;

*对组件dynamicComponent的操作,可通过以下代码进行,例如,动态组件TestComponent中有@Input() Data,可通过.data进行赋值;

(<any>dynamicComponent.instance).data = "test";

至此,为我对动态组件的理解。利用动态组件的Table控件实现会整理进下一篇文章

相关文章

AngularJS 是一个JavaScript 框架。它可通过 注:建议把脚本放在 元素的底部。这会提高网页加载速度,因...
angluarjs中页面初始化的时候会出现语法{{}}在页面中问题,也即是页面闪烁问题。出现这个的原因是:由于...
AngularJS 通过被称为指令的新属性来扩展 HTML。AngularJS 指令AngularJS 指令是扩展的 HTML 属性,带有...
AngularJS 使用表达式把数据绑定到 HTML。AngularJS 表达式AngularJS 表达式写在双大括号内:{{ expres...
ng-repeat 指令可以完美的显示表格。在表格中显示数据 {{ x.Name }} {{ x.Country }} 使用 CSS 样式为了...
$http是 AngularJS 中的一个核心服务,用于读取远程服务器的数据。读取 JSON 文件下是存储在web服务器上...