您的位置:首页 > Web前端 > AngularJS

angular 学习笔记 ( Dynamic Component 动态组件)

2018-01-26 10:32 519 查看
动态组件分 2 种 

1. Jit

2. Aot

Jit 的情况下你可以动态的写组件模板, 最后 append 出去, 类似 ng1 的 $compile 

Aot 的话, 模板是固定的, 我们只是可以动态创建 component 然后 append 出去

这一篇只会谈及 Aot 

 

要知道的事项 : 

1. 所有要动态的组件除了需要 declarations之外还要声明到 entryComponents 里头, 原因是 ng 是通过扫描模板来 import component class 的, 动态组件不会出现在模板上所以我们要用另一个 way 告诉 ng。

providers: [
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: [AComponentClass, BComponentClass], multi: true}
]


要方便扩展的话可以用 provides, ng-router 也是用这个实现的.

2. 目前只有动态组件,没有动态指令 (呃..所以动态创建的组件就不能附带指令咯.../.\)

3. 例子 

@Component({
selector: 'aaa',
template: ``
})
export class AAAComponent implements OnInit, AfterContentInit {
constructor(
private vcr: ViewContainerRef,
private cfr: ComponentFactoryResolver
) { }

@ContentChildren("dynamic", { read: ElementRef }) elem: QueryList<ElementRef>  //read 的作用是强转类型

ngOnInit() {

}

ngAfterContentInit() {
let providers = ReflectiveInjector.resolve([AbcService]); //为组件添加 providers
let injector = ReflectiveInjector.fromResolvedProviders(providers, this.vcr.parentInjector); //创建注入器给 component (记得要继承哦)
let factory = this.cfr.resolveComponentFactory(AbcComponent); //创建 component 工厂
let component = factory.create(injector,[[this.elem.first.nativeElement],[this.elem.last.nativeElement] ]); //创建 component, 这是就把注入器放进了, 后面的 array 是给 ng-content 用的
component.instance.name = "keatkeat"; // 对 input, output 做点东西
this.vcr.insert(component.hostView, 0); // 插入到模板中  0 是 position, 如果是 0 其实可以不用放.

// 如果不需要设定 providers 的话,可以省略一些 :
// let factory = this.resolver.resolveComponentFactory(AbcComponent);
// let component = this.vcr.createComponent(factory, 0);
// component.instance.name = "keatkeat";
}
}


里头说的 ng-content, 就是 Projectable nodes , 我个人认为这个做法还不太理想,因为 ng-content 应该是可以通过 select 找到对应的 tranclude 的,不过这里的参数 array 已经固定了 tranclude 的位置. 

所以目前, 如果你要做类似 tranclude 的事情, 改用 input 传递 templateRef 反而会比较容易控制. 

类似这样 

@Component({
template : `
<p>final</p>
<template [ngTemplateOutlet]="template" [ngOutletContext]="{ innerValue : 'huhu' }" ></template>
`,
selector : "final"
})
export class FinalComponent implements OnInit {
constructor(
) { }

@Input()
template : TemplateRef<any> //传进来

ngOnInit() {
console.log(this.template);
}
}


 4. 个人的想法 

一个动态组件应该和平时的组件必须是一样的,意思是我们可以随时把任何一个组件改成动态调用的方式. 

不过目前 ng 支持的不是很好

-input, output (支持)

-tranclude (Projectable nodes 显然和 ng-content配合不上)

-在 component 上放指令 (动态创建的 component, 没办法加上指令, 这导致了 dynamic accessor 很难写)

例子 

@Component({
templateUrl : "./debugTwo.component.html"
})
export class DebugTwoComponent implements OnInit, AfterViewInit {

constructor(
private fb : FormBuilder,
private cfr : ComponentFactoryResolver
) { }

form : FormGroup
@ViewChild("target", { read : ViewContainerRef }) target : ViewContainerRef
ngOnInit() {

this.form = this.fb.group({
age : [0]
});
}

ngAfterViewInit()
{
let factory = this.cfr.resolveComponentFactory(AccessorComponent);
let component = this.target.createComponent(factory, 0);
let ctrl = this.form.controls["age"];
component.instance.writeValue(ctrl.value); //需要手动去调用 writeValue, registerOnChange, registerOnTouched, 如果可以直接加上 formControlName 指令,就方便多了.
component.instance.registerOnChange((v) => {
ctrl.setValue(v);
});
//component.instance.template = this.template;
}
}


 

5. 一些常用到的类 

-ViewContainerRef : 好比一个 root div, 通常我们引用它目的就是 append element 进去.

 常用 : createEmbeddedView, createComponent, insert

-TemplateRef : 指的是 <template> 里面的内容.  

 常用 : createEmbeddedView

-ElementRef : dom 

 常用 : nativeElement (获取 dom 对象引用)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  angular